diff --git a/.gitignore b/.gitignore index a591128..88a9696 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ /bin/ -/build/ /.idea/ -/assets/*.txt +/src/target/ +/cmake-build/ /cmake-build-debug/ /cmake-build-release/ -/src/to-json/target/ + +/assets/*.txt +/include/constant.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e793597..d93e542 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,41 @@ cmake_minimum_required(VERSION 2.8.12) -project(cleardns) -set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) +project(cleardns LANGUAGES C) + +set(CMAKE_C_STANDARD 99) + +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror") + +############################################################### + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +############################################################### + +macro(git_tag _tag) + find_package(Git QUIET) + if (GIT_FOUND) + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags + OUTPUT_VARIABLE ${_tag} + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) + endif() +endmacro() + +set(VERSION "") +git_tag(VERSION) +if(VERSION STREQUAL "") # without git tag + message(FATAL_ERROR "Git command not found") +endif() + +############################################################### add_subdirectory(src) + +############################################################### diff --git a/Dockerfile b/Dockerfile index 5fab6de..194e546 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ ARG ALPINE="alpine:3.17" -ARG RUST="rust:1.65-alpine3.16" +ARG RUST="rust:1.67-alpine3.17" ARG GOLANG="golang:1.18-alpine3.16" FROM ${ALPINE} AS upx RUN apk add build-base cmake -ENV UPX="4.0.1" +ENV UPX="4.0.2" RUN wget https://github.com/upx/upx/releases/download/v${UPX}/upx-${UPX}-src.tar.xz && tar xf upx-${UPX}-src.tar.xz WORKDIR ./upx-${UPX}-src/ RUN make UPX_CMAKE_CONFIG_FLAGS=-DCMAKE_EXE_LINKER_FLAGS=-static @@ -38,21 +38,23 @@ RUN env CGO_ENABLED=0 go build -v -trimpath -ldflags "-X main.VersionString=${DN COPY --from=upx /tmp/upx /usr/bin/ RUN upx -9 /tmp/dnsproxy -FROM ${RUST} AS to-json -COPY ./src/to-json/ /to-json/ -WORKDIR /to-json/ -RUN cargo build --release -RUN cp ./target/release/libto_json.a / +FROM ${RUST} AS rust-mods +RUN apk add libc-dev openssl-dev +COPY ./src/ /cleardns/ +WORKDIR /cleardns/ +RUN cargo fetch +RUN cargo build --release && mv ./target/release/*.a /tmp/ FROM ${ALPINE} AS cleardns -RUN apk add build-base cmake +RUN apk add build-base cmake git openssl-libs-static COPY ./ /cleardns/ -COPY --from=to-json /libto_json.a /cleardns/src/to-json/target/release/ +COPY --from=rust-mods /tmp/libassets.a /cleardns/src/target/release/ +COPY --from=rust-mods /tmp/libto_json.a /cleardns/src/target/release/ WORKDIR /cleardns/bin/ -RUN cmake -DCMAKE_EXE_LINKER_FLAGS=-static -DCMAKE_BUILD_TYPE=Release .. && make -RUN strip cleardns && mv cleardns /tmp/ +RUN cmake -DCMAKE_EXE_LINKER_FLAGS=-static .. && make && mv cleardns /tmp/ COPY --from=upx /tmp/upx /usr/bin/ -RUN upx -9 /tmp/cleardns +WORKDIR /tmp/ +RUN strip cleardns && upx -9 cleardns FROM ${ALPINE} AS build RUN apk add xz diff --git a/assets/china-ip.py b/assets/china-ip.py index 7a2f8ef..94f06dc 100755 --- a/assets/china-ip.py +++ b/assets/china-ip.py @@ -22,7 +22,8 @@ for ipAddr in ipAddrs: try: ip = IP(ipAddr) # ip format check (ipv4 if ip.version() == 4 else ipv6).add(ip) - except: pass + except: + pass release = [('%s' if '/' in str(ip) else '%s/32') % str(ip) for ip in ipv4] # format into CIDR release += [('%s' if '/' in str(ip) else '%s/128') % str(ip) for ip in ipv6] diff --git a/include/bcrypt/bcrypt.h b/include/bcrypt/bcrypt.h index d7d4df8..3d7e35e 100644 --- a/include/bcrypt/bcrypt.h +++ b/include/bcrypt/bcrypt.h @@ -60,10 +60,16 @@ int bcrypt_hashpw(const char *passwd, const char salt[BCRYPT_HASHSIZE], int bcrypt_checkpw(const char *passwd, const char hash[BCRYPT_HASHSIZE]); /* - * This function expects a string and return bcrypt result (random salt) + * This function expects a string and return bcrypt result with random salt. */ -char* bcrypt_cal(const char *data); +char* bcrypt_hash(const char *data); + +/* + * This function verifies that the data matches the hash value. + */ + +int bcrypt_verify(const char *data, const char *hash); /* * Brief Example diff --git a/include/common/json.h b/include/common/json.h index 345f408..c3a4cfc 100644 --- a/include/common/json.h +++ b/include/common/json.h @@ -4,7 +4,7 @@ #include #include "cJSON.h" -char* to_json(const char *content); +char* to_json_format(const char *content); uint8_t is_json_suffix(const char *file_name); cJSON* json_field_get(cJSON *entry, const char *key); void json_field_replace(cJSON *entry, const char *key, cJSON *content); @@ -14,6 +14,5 @@ uint8_t json_bool_value(char *caption, cJSON *json); char* json_string_value(char* caption, cJSON *json); char** json_string_list_value(char *caption, cJSON *json, char **string_list); uint32_t** json_uint32_list_value(char *caption, cJSON *json, uint32_t **uint32_list); -void json_string_map_value(char *caption, cJSON *json, char ***key_list, char ***value_list); #endif diff --git a/include/common/sundry.h b/include/common/sundry.h index 97f53ca..09a3b8e 100644 --- a/include/common/sundry.h +++ b/include/common/sundry.h @@ -3,8 +3,8 @@ #include -char* show_bool(uint8_t value); uint8_t check_port(uint16_t port); +const char* show_bool(uint8_t value); char* string_load(const char *fmt, ...); char* uint32_to_string(uint32_t number); char* string_join(const char *base, const char *add); diff --git a/include/common/system.h b/include/common/system.h index b8860d9..39e340b 100644 --- a/include/common/system.h +++ b/include/common/system.h @@ -8,7 +8,6 @@ int run_command(const char *command); void create_folder(const char *folder); uint8_t is_file_exist(const char *file); void save_file(const char *file, const char *content); -void download_file(const char *file, const char *url); void save_string_list(const char *file, char **string_list); void file_append(const char *base_file, const char *append_file); diff --git a/include/constant.h b/include/constant.h.in similarity index 97% rename from include/constant.h rename to include/constant.h.in index 03390d2..768409c 100644 --- a/include/constant.h +++ b/include/constant.h.in @@ -13,7 +13,7 @@ #define RESTART_DELAY 1 #define DIVERTER_TIMEOUT 6 -#define VERSION "1.3.3" +#define VERSION "@VERSION@" #define CONFIG_FILE "cleardns.yml" #define DNSPROXY_BIN "dnsproxy" diff --git a/include/loader/config.h b/include/loader/config.h index 2a2f9bc..db80ff8 100644 --- a/include/loader/config.h +++ b/include/loader/config.h @@ -2,6 +2,7 @@ #define CONFIG_H_ #include +#include "assets.h" typedef struct { uint16_t port; @@ -34,10 +35,9 @@ typedef struct { } adguard_config; typedef struct { - uint8_t disable; // bool value char *cron; - char **update_file; - char **update_url; + uint8_t disable; // bool value + asset **resources; } assets_config; typedef struct { diff --git a/include/loader/loader.h b/include/loader/loader.h index fb68648..27a011d 100644 --- a/include/loader/loader.h +++ b/include/loader/loader.h @@ -15,11 +15,13 @@ struct cleardns { overture *diverter; adguard *filter; crontab *crond; - assets *resource; + asset **resource; }; extern struct cleardns loader; +void load_diverter_assets(); + void load_config(const char *config_file); #endif diff --git a/include/to_json.h b/include/to_json.h index a728d81..b1b7f46 100644 --- a/include/to_json.h +++ b/include/to_json.h @@ -1,12 +1,17 @@ #pragma once -/* Generated with cbindgen:0.23.0 */ - #include #include #include #include +/** + * Free the exported c-style string. + */ void free_rust_string(const char *ptr); -const char *to_json_ffi(const char *content); +/** + * Format the input text into JSON format and return a c-style string, or return + * `NULL` if an error occurs. + */ +const char *to_json(const char *content); diff --git a/include/utils/assets.h b/include/utils/assets.h index 5e1b47b..51279c1 100644 --- a/include/utils/assets.h +++ b/include/utils/assets.h @@ -1,15 +1,29 @@ #ifndef ASSETS_H_ #define ASSETS_H_ -typedef struct { - char **update_file; - char **update_url; -} assets; +#include + +extern char **custom_gfwlist; +extern char **custom_china_ip; +extern char **custom_chinalist; -assets* assets_init(); -void assets_free(assets *info); -void assets_load(assets *info); +typedef struct { + char *file; // string + char **sources; // string list +} asset; void assets_extract(); +void assets_load(asset **info); + +asset** assets_init(); +asset* asset_init(const char *name); +void assets_dump(asset **asset_list); +void assets_free(asset **asset_list); +uint32_t assets_size(asset **asset_list); +void assets_append(asset ***asset_list, asset *res); + +/// Rust assets interface +void assets_log_init(uint8_t verbose); +uint8_t asset_update(const char *file, char *const *sources, const char *assets_dir); #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index afa07b3..51cb6ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,12 @@ include_directories(${PROJECT_SOURCE_DIR}/include/bcrypt) include_directories(${PROJECT_SOURCE_DIR}/include/common) include_directories(${PROJECT_SOURCE_DIR}/include/loader) -link_directories(${PROJECT_SOURCE_DIR}/src/to-json/target/release) +link_directories(${PROJECT_SOURCE_DIR}/src/target/release) + +configure_file( + ${PROJECT_SOURCE_DIR}/include/constant.h.in + ${PROJECT_SOURCE_DIR}/include/constant.h +) add_subdirectory(utils) add_subdirectory(applet) diff --git a/src/Cargo.lock b/src/Cargo.lock new file mode 100644 index 0000000..6621f5f --- /dev/null +++ b/src/Cargo.lock @@ -0,0 +1,1275 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "assets" +version = "0.1.0" +dependencies = [ + "env_logger", + "log", + "reqwest", + "tokio", +] + +[[package]] +name = "async-compression" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" + +[[package]] +name = "futures-sink" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" + +[[package]] +name = "futures-task" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" + +[[package]] +name = "futures-util" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "h2" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +dependencies = [ + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + +[[package]] +name = "is-terminal" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.45.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "openssl" +version = "0.10.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "reqwest" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +dependencies = [ + "async-compression", + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rustix" +version = "0.36.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" + +[[package]] +name = "serde_json" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82e6c8c047aa50a7328632d067bcae6ef38772a79e28daf32f735e0e4f3dd10" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.42.0", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "to_json" +version = "0.1.0" +dependencies = [ + "serde_json", + "serde_yaml", + "toml", +] + +[[package]] +name = "tokio" +version = "1.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.45.0", +] + +[[package]] +name = "tokio-macros" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "unicode-bidi" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2024452afd3874bf539695e04af6732ba06517424dbf958fdb16a01f3bef6c" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "winnow" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95fb4ff192527911dd18eb138ac30908e7165b8944e528b6af93aa4c842d345" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] diff --git a/src/Cargo.toml b/src/Cargo.toml new file mode 100644 index 0000000..150e4f8 --- /dev/null +++ b/src/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +members = [ + "assets", + "to-json" +] diff --git a/src/applet/adguard.c b/src/applet/adguard.c index 5f85c13..1a8e2ab 100644 --- a/src/applet/adguard.c +++ b/src/applet/adguard.c @@ -46,9 +46,26 @@ char *adguard_config(adguard *info, const char *raw_config) { // modify adguard log_fatal("AdGuardHome configure error"); } + char *password = NULL; + cJSON *user_passwd = cJSON_GetObjectItem(cJSON_GetArrayItem( + cJSON_GetObjectItem(json, "users"), 0), "password"); + if (cJSON_IsString(user_passwd)) { + char *hash_val = user_passwd->valuestring; + log_debug("Legacy hash value -> `%s`", hash_val); + if (bcrypt_verify(info->password, hash_val)) { + log_debug("Legacy hash value verify success"); + password = strdup(hash_val); + } else { + log_debug("Legacy hash value verify failed"); + } + } + if (password == NULL) { // password hash not ready + password = bcrypt_hash(info->password); + } + log_debug("AdGuardHome password -> `%s`", password); + cJSON *user_config = cJSON_CreateObject(); // setting up username and password cJSON *users_config = cJSON_CreateArray(); - char *password = bcrypt_cal(info->password); cJSON_AddItemToObject(user_config, "name", cJSON_CreateString(info->username)); cJSON_AddItemToObject(user_config, "password", cJSON_CreateString(password)); cJSON_AddItemToArray(users_config, user_config); @@ -93,7 +110,7 @@ process* adguard_load(adguard *info, const char *dir) { // load adguard options adguard_config_ret = adguard_config(info, "{}"); // begin with empty json } else { // configure exist -> modify char *adguard_config_content = read_file(adguard_config_file); - char *adguard_config_json = to_json(adguard_config_content); + char *adguard_config_json = to_json_format(adguard_config_content); adguard_config_ret = adguard_config(info, adguard_config_json); free(adguard_config_content); free(adguard_config_json); diff --git a/src/assets/Cargo.toml b/src/assets/Cargo.toml new file mode 100644 index 0000000..761f136 --- /dev/null +++ b/src/assets/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "assets" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["staticlib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +env_logger = "0.10.0" +log = "0.4.17" +reqwest = { version = "0.11.14", features = ["deflate", "gzip", "brotli"] } +tokio = { version = "1.26.0", features = ["macros", "rt-multi-thread"] } diff --git a/src/assets/cbindgen.toml b/src/assets/cbindgen.toml new file mode 100644 index 0000000..0555597 --- /dev/null +++ b/src/assets/cbindgen.toml @@ -0,0 +1,3 @@ +language = "C" +pragma_once = true +include_version = false diff --git a/src/assets/src/fetch.rs b/src/assets/src/fetch.rs new file mode 100644 index 0000000..ca399ff --- /dev/null +++ b/src/assets/src/fetch.rs @@ -0,0 +1,193 @@ +use std::fs::File; +use std::io::Read; +use reqwest::Client; +use std::time::Duration; +use log::{debug, info, warn}; +use std::collections::HashSet; + +/// Http download timeout limit +const TIMEOUT: u64 = 120; + +/// Cut text line by line and remove invisible characters on both sides. +fn asset_tidy(data: &str) -> Vec { + data.lines() + .map(|x| String::from(x.trim())) + .filter(|x| !x.is_empty()) + .collect() +} + +/// Remove duplicate elements from an array. +fn remove_dup(data: &Vec) -> Vec { + let mut result: Vec = vec![]; + let mut tmp: HashSet = HashSet::new(); + for val in data { + if tmp.insert(val.clone()) { // value already exist + result.push(val.clone()); + } + } + result +} + +/// Download the specified text file and organize it into a String array. +async fn http_fetch(url: &str, timeout: u64) -> Result, String> { + let client = Client::builder() + .timeout(Duration::from_secs(timeout)) + .build().unwrap(); + debug!("Start downloading `{}`", url); + match client.get(url).send().await { + Ok(response) => { + match response.text().await { + Ok(text) => { + info!("Remote file `{}` download success", url); + Ok(asset_tidy(&text)) + }, + Err(err) => Err(format!("http content error: {}", err)) + } + }, + Err(err) => Err(format!("http request failed: {}", err)) + } +} + +/// Read the specified text file and organize it into a String array. +async fn local_fetch(path: &str) -> Result, String> { + match File::open(path) { + Ok(mut file) => { + let mut text = String::new(); + if let Err(err) = file.read_to_string(&mut text) { + return Err(format!("file `{}` read failed: {}", path, err)); + }; + info!("Local file `{}` read success", path); + Ok(asset_tidy(&text)) + }, + Err(err) => Err(format!("file `{}` open failed: {}", path, err)), + } +} + +/// Get multiple resource data and merge them. +pub(crate) async fn asset_fetch(name: &str, sources: &Vec) -> Option> { + let is_remote = |src: &str| { + src.starts_with("http://") || src.starts_with("https://") + }; + let mut contents: Vec> = vec![]; + for source in sources { + contents.push(match if is_remote(&source) { + http_fetch(source.trim(), TIMEOUT).await // from remote text file + } else { + local_fetch(source.trim()).await // from local text file + } { + Ok(data) => { + debug!("Asset source `{}` fetch success with {} items", source.trim(), data.len()); + data + }, + Err(err) => { + warn!("Asset source `{}` fetch failed: {}", source.trim(), err); + return None; // stop fetch process + } + }); + } + let contents = remove_dup(&contents + .into_iter() + .flatten() + .collect::>()); + info!("Asset `{}` fetch complete with {} items", name, contents.len()); + Some(contents) +} + +#[cfg(test)] +mod tests { + use std::fs; + use std::pin::Pin; + use std::future::Future; + use std::fs::OpenOptions; + use std::io::Write; + use super::{asset_tidy, remove_dup}; + use super::{http_fetch, local_fetch, asset_fetch}; + + const TEST_DATA: &str = "\tabc \n123 \n 456\r\nabc\n\n789 "; + + #[test] + fn basic() { + assert_eq!(asset_tidy(TEST_DATA), vec![ + String::from("abc"), + String::from("123"), + String::from("456"), + String::from("abc"), + String::from("789"), + ]); + assert_eq!(remove_dup(&asset_tidy(TEST_DATA)), vec![ + String::from("abc"), + String::from("123"), + String::from("456"), + String::from("789"), + ]); + } + + fn run_async(func: Pin>>) { + tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap() + .block_on(func); + } + + fn gen_test_file() { + let mut fp = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open("/tmp/assets_test_file") + .unwrap(); + fp.write_all(TEST_DATA.as_ref()).expect("test file create error"); + } + + #[test] + fn asset() { + // test http_fetch function + run_async(Box::pin(async { + assert!(http_fetch("invalid url", 10).await.is_err()); + assert_eq!( + http_fetch("https://gstatic.com/generate_204", 10).await, + Ok(vec![]) + ); + })); + + // test local_fetch function + gen_test_file(); + run_async(Box::pin(async { + assert!(local_fetch("/").await.is_err()); + assert_eq!( + local_fetch("/tmp/assets_test_file").await, + Ok(vec![ + String::from("abc"), + String::from("123"), + String::from("456"), + String::from("abc"), + String::from("789"), + ]) + ); + })); + + // test combine asset_fetch function + run_async(Box::pin(async { + assert!( + asset_fetch("", &vec![]).await.unwrap().is_empty() + ); + assert!( + asset_fetch("", &vec![String::from("...")]).await.is_none() + ); + assert_eq!( + asset_fetch("", &vec![ + String::from("/tmp/assets_test_file"), + String::from("https://gstatic.com/generate_204") + ]).await, + Some(vec![ + String::from("abc"), + String::from("123"), + String::from("456"), + String::from("789"), + ]) + ); + })); + fs::remove_file("/tmp/assets_test_file").expect("test file delete error"); + } +} diff --git a/src/assets/src/ffi.rs b/src/assets/src/ffi.rs new file mode 100644 index 0000000..6cb3663 --- /dev/null +++ b/src/assets/src/ffi.rs @@ -0,0 +1,97 @@ +use std::io::Write; +use std::env::set_var; +use std::path::PathBuf; +use std::fs::OpenOptions; +use std::os::raw::c_char; +use log::{debug, trace, warn}; +use std::ffi::{CStr, CString}; +use crate::fetch::asset_fetch; + +/// Compatible with C89 bool value. +const TRUE: u8 = 1; +const FALSE: u8 = 0; + +/// Load c-style string from `char *` pointer. +unsafe fn load_c_string(ptr: *const c_char) -> String { + CString::from(CStr::from_ptr(ptr)) + .into_string() + .unwrap() +} + +/// Load c-style string list from `char **` pointer. +unsafe fn load_c_string_list(ptr: *const *const c_char) -> Vec { + let mut index = 0; + let mut string_list: Vec = vec![]; + while *ptr.offset(index) != std::ptr::null() { // traverse until `NULL` + string_list.push(load_c_string(*ptr.offset(index))); + index += 1; + } + string_list +} + +/// Initialize the rust module log, enable trace level log when verbose is not `0`. +#[no_mangle] +pub unsafe extern "C" fn assets_log_init(verbose: u8) { + if verbose == FALSE { // bool value `FALSE` + set_var("RUST_LOG", "info"); + } else { + set_var("RUST_LOG", "trace"); + } + env_logger::init(); +} + +/// Update the specified resource file, return `0` on failure. +#[no_mangle] +#[tokio::main] +pub async unsafe extern "C" fn asset_update( + file: *const c_char, sources: *const *const c_char, assets_dir: *const c_char) -> u8 { + + let name = load_c_string(file); // import c-style string + let sources = load_c_string_list(sources); + let assets_dir = load_c_string(assets_dir); + trace!("Working folder is `{}`", assets_dir); + trace!("Updating `{}` from {:?}", name, sources); + + let assets_dir = PathBuf::from(&assets_dir); + let is_remote = |src: &str| { + src.starts_with("http://") || src.starts_with("https://") + }; + let sources = sources.iter() + .map(|src| { + if !is_remote(&src) && !src.starts_with("/") { // local relative path + let file_path = assets_dir.join(src); + String::from(file_path.to_str().unwrap()) + } else { + src.clone() + } + }) + .collect::>(); + let file = String::from(assets_dir.join(&name).to_str().unwrap()); + debug!("Asset sources -> {:?}", sources); + debug!("Asset target -> `{}`", file); + + match asset_fetch(&name, &sources).await { + Some(data) => { + let mut content = String::new(); + let _ = data.iter().map(|item| { + content.push_str(item); + content.push('\n'); + }).collect::>(); + match OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&file) { // open target file + Ok(mut fp) => { + match fp.write_all(content.as_ref()) { + Err(err) => warn!("File `{}` save error: {}", file, err), + _ => debug!("File `{}` save success", file), + } + }, + Err(err) => warn!("File `{}` open failed: {}", file, err), + }; + TRUE // asset fetch success + }, + None => FALSE, // asset fetch failed + } +} diff --git a/src/assets/src/lib.rs b/src/assets/src/lib.rs new file mode 100644 index 0000000..937b6d5 --- /dev/null +++ b/src/assets/src/lib.rs @@ -0,0 +1,2 @@ +mod ffi; +mod fetch; diff --git a/src/bcrypt/hash.c b/src/bcrypt/hash.c index 929ff20..60b1200 100644 --- a/src/bcrypt/hash.c +++ b/src/bcrypt/hash.c @@ -1,8 +1,9 @@ #include #include "bcrypt.h" #include "logger.h" +#include "constant.h" -char* bcrypt_cal(const char *data) { +char* bcrypt_hash(const char *data) { char salt[BCRYPT_HASHSIZE]; log_debug("BCrypt data -> `%s`", data); if (bcrypt_gensalt(10, salt)) { @@ -17,3 +18,10 @@ char* bcrypt_cal(const char *data) { log_debug("BCrypt hash -> `%s`", hash); return hash; } + +int bcrypt_verify(const char *data, const char *hash) { + if (bcrypt_checkpw(data, hash) == 0) { + return TRUE; + } + return FALSE; +} diff --git a/src/cleardns.c b/src/cleardns.c index 31c85a3..492c8fc 100644 --- a/src/cleardns.c +++ b/src/cleardns.c @@ -5,7 +5,6 @@ #include #include "loader.h" #include "logger.h" -#include "sundry.h" #include "system.h" #include "assets.h" #include "adguard.h" @@ -67,6 +66,9 @@ void init(int argc, char *argv[]) { // return config file void cleardns() { // cleardns service if (settings.verbose || settings.debug) { LOG_LEVEL = LOG_DEBUG; // enable debug log level + assets_log_init(TRUE); + } else { + assets_log_init(FALSE); } create_folder(EXPOSE_DIR); create_folder(WORK_DIR); diff --git a/src/common/json.c b/src/common/json.c index 4264824..eda5809 100644 --- a/src/common/json.c +++ b/src/common/json.c @@ -17,20 +17,18 @@ uint8_t is_json_suffix(const char *file_name) { // whether file name end with `. return FALSE; } -char* to_json(const char *content) { // convert JSON / TOML / YAML to json format (failed -> NULL) - const char *json_string = to_json_ffi(content); // convert to json format - char *json_content = strdup(json_string); // load string into owner heap - free_rust_string(json_string); // free rust string - if (strlen(json_content) == 0) { // empty string -> convert error +char* to_json_format(const char *content) { // convert JSON / TOML / YAML to json format (failed -> NULL) + const char *json_string = to_json(content); // convert to json format + if (json_string == NULL) { log_warn("JSON convert error ->\n%s", content); - free(json_content); - return NULL; + return NULL; // convert failed } + char *json_content = strdup(json_string); // load string into owner heap + free_rust_string(json_string); // free rust string log_debug("JSON convert result ->\n%s", json_content); return json_content; } - cJSON* json_field_get(cJSON *entry, const char *key) { // fetch key from json map (create when key not exist) cJSON *sub = entry->child; while (sub != NULL) { // traverse all keys @@ -115,18 +113,3 @@ uint32_t** json_uint32_list_value(char *caption, cJSON *json, uint32_t **uint32_ } return uint32_list; } - -void json_string_map_value(char *caption, cJSON *json, char ***key_list, char ***value_list) { // json string map - if (!cJSON_IsObject(json)) { - log_fatal("`%s` must be map", caption); - } - json = json->child; - while (json != NULL) { // traverse all json field - if (!cJSON_IsString(json)) { - log_fatal("`%s` must be string-string map", caption); - } - string_list_append(key_list, json->string); - string_list_append(value_list, json->valuestring); - json = json->next; - } -} diff --git a/src/common/sundry.c b/src/common/sundry.c index a203505..b09a213 100644 --- a/src/common/sundry.c +++ b/src/common/sundry.c @@ -10,7 +10,7 @@ #include "constant.h" #include "structure.h" -char* show_bool(uint8_t value) { // return `true` or `false` +const char* show_bool(uint8_t value) { // return `true` or `false` if (value) { return "true"; } @@ -49,7 +49,7 @@ void uint32_list_debug(char *describe, uint32_t **uint32_list) { // show uint32 } uint8_t check_port(uint16_t port) { // whether port is valid - if (port > 0 && port <= 65535) { // 1 ~ 65535 + if (port > 0) { // 1 ~ 65535 (uint16_t <= 65535) return TRUE; } return FALSE; diff --git a/src/common/system.c b/src/common/system.c index 0dc3c78..74dc663 100644 --- a/src/common/system.c +++ b/src/common/system.c @@ -95,11 +95,3 @@ void save_string_list(const char *file, char **string_list) { // save string lis fclose(fp); log_debug("Save `%s` success", file); } - -void download_file(const char *file, const char *url) { // download file - log_debug("Download file `%s` -> %s", file, url); - char *download_cmd = string_load("wget -T 8 -O %s %s", file, url); - if (run_command(download_cmd)) { - log_warn("File `%s` download failed", url); - } -} diff --git a/src/loader/config.c b/src/loader/config.c index f462337..4b55a94 100644 --- a/src/loader/config.c +++ b/src/loader/config.c @@ -41,8 +41,7 @@ cleardns_config* config_init() { // init config struct of cleardns config->assets.disable = FALSE; config->assets.cron = strdup(UPDATE_CRON); - config->assets.update_file = string_list_init(); - config->assets.update_url = string_list_init(); + config->assets.resources = assets_init(); config->reject = uint32_list_init(); config->hosts = string_list_init(); @@ -85,10 +84,8 @@ void config_dump(cleardns_config *config) { // dump config info of cleardns log_debug("Assets disable -> %s", show_bool(config->assets.disable)); log_debug("Assets update cron -> `%s`", config->assets.cron); - for (char **file = config->assets.update_file; *file != NULL; ++file) { // show string mapping - char **url = file - config->assets.update_file + config->assets.update_url; - log_debug("Assets file `%s` -> %s", *file, *url); - } + log_debug("Assets with %d resource items", assets_size(config->assets.resources)); + assets_dump(config->assets.resources); uint32_list_debug("DNS reject type", config->reject); string_list_debug("Domain TTL", config->ttl); @@ -113,8 +110,7 @@ void config_free(cleardns_config *config) { // free config struct of cleardns free(config->adguard.password); free(config->assets.cron); - string_list_free(config->assets.update_file); - string_list_free(config->assets.update_url); + assets_free(config->assets.resources); uint32_list_free(config->reject); string_list_free(config->hosts); diff --git a/src/loader/default.c b/src/loader/default.c index e964484..ade85f7 100644 --- a/src/loader/default.c +++ b/src/loader/default.c @@ -51,13 +51,13 @@ assets:\n\ void load_default_config(const char *config_file) { if (is_file_exist(config_file)) { - log_debug("Configure file exist -> skip load default"); + log_debug("Configure file exist -> skip loading default"); return; } log_info("Loading default configure file"); char *config_content = NULL; if (is_json_suffix(config_file)) { // convert to json format - config_content = to_json(DEFAULT_CONFIG); + config_content = to_json_format(DEFAULT_CONFIG); } else { config_content = strdup(DEFAULT_CONFIG); } diff --git a/src/loader/loader.c b/src/loader/loader.c index 09b3bd2..6d2e30f 100644 --- a/src/loader/loader.c +++ b/src/loader/loader.c @@ -95,6 +95,13 @@ overture* load_diverter(cleardns_config *config) { free(china_ip); free(gfwlist); + custom_gfwlist = config->diverter.gfwlist; + custom_china_ip = config->diverter.china_ip; + custom_chinalist = config->diverter.chinalist; + config->diverter.gfwlist = string_list_init(); + config->diverter.china_ip = string_list_init(); + config->diverter.chinalist = string_list_init(); + uint32_list_update(&diverter->reject_type, config->reject); if (!config->assets.disable) { assets_extract(); // extract built-in resource @@ -127,11 +134,13 @@ crontab* load_crond(cleardns_config *config) { return crond; } -assets* load_assets(cleardns_config *config) { - assets *resource = assets_init(); - string_list_update(&resource->update_file, config->assets.update_file); - string_list_update(&resource->update_url, config->assets.update_url); - return resource; +asset** load_assets(cleardns_config *config) { + asset **resources = assets_init(); + for (asset **res = config->assets.resources; *res != NULL; ++res) { + assets_append(&resources, *res); // pointer movement + } + *(config->assets.resources) = NULL; // disable old assets list + return resources; } void load_config(const char *config_file) { // parser and load cleardns configure diff --git a/src/loader/parser.c b/src/loader/parser.c index ca8d9d7..b6f2c66 100644 --- a/src/loader/parser.c +++ b/src/loader/parser.c @@ -130,7 +130,18 @@ void assets_parser(assets_config *config, cJSON *json) { // assets options parse config->cron = json_string_value("assets.cron", json); } if (!strcmp(json->string, "update")) { - json_string_map_value("assets.update", json, &config->update_file, &config->update_url); + if (!cJSON_IsObject(json)) { + log_fatal("`%s` must be map", "assets.update"); + } + cJSON *asset_item = json->child; + while (asset_item != NULL) { // traverse all json field + asset *res = asset_init(asset_item->string); + char *caption = string_join("assets.update.", asset_item->string); + res->sources = json_string_list_value(caption, asset_item, res->sources); + free(caption); + assets_append(&config->resources, res); + asset_item = asset_item->next; + } } json = json->next; // next field } @@ -188,7 +199,7 @@ void config_parser(cleardns_config *config, const char *config_file) { log_info("Start JSON configure parser"); } else { // YAML or TOML format log_info("Start configure parser"); - char *convert_ret = to_json(config_content); + char *convert_ret = to_json_format(config_content); if (convert_ret == NULL) { // convert failed log_fatal("Configure parser error"); } diff --git a/src/to-json/Cargo.lock b/src/to-json/Cargo.lock deleted file mode 100644 index 7b043cc..0000000 --- a/src/to-json/Cargo.lock +++ /dev/null @@ -1,91 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "serde" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" - -[[package]] -name = "serde_json" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d232d893b10de3eb7258ff01974d6ee20663d8e833263c99409d4b13a0209da" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - -[[package]] -name = "to-json" -version = "0.1.0" -dependencies = [ - "serde_json", - "serde_yaml", - "toml", -] - -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - -[[package]] -name = "unsafe-libyaml" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68" diff --git a/src/to-json/Cargo.toml b/src/to-json/Cargo.toml index d4202a8..c2a0eda 100644 --- a/src/to-json/Cargo.toml +++ b/src/to-json/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "to-json" +name = "to_json" version = "0.1.0" edition = "2021" @@ -9,6 +9,6 @@ crate-type = ["staticlib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde_json = "1.0.89" -serde_yaml = "0.9.14" -toml = "0.5.9" +serde_json = "1.0.94" +serde_yaml = "0.9.19" +toml = "0.7.2" diff --git a/src/to-json/cbindgen.toml b/src/to-json/cbindgen.toml index cb8d3fd..0555597 100644 --- a/src/to-json/cbindgen.toml +++ b/src/to-json/cbindgen.toml @@ -1,3 +1,3 @@ language = "C" pragma_once = true -include_version = true +include_version = false diff --git a/src/to-json/src/ffi.rs b/src/to-json/src/ffi.rs index f728598..5f147c8 100644 --- a/src/to-json/src/ffi.rs +++ b/src/to-json/src/ffi.rs @@ -1,27 +1,130 @@ -use crate::json::to_json; -use std::ffi::{c_char, CStr, CString}; +use std::os::raw::c_char; +use std::ffi::{CStr, CString}; +use crate::parser::{parser, Value}; -fn to_c_string(string: String) -> *const c_char { // fetch c-style ptr of string - CString::new(string).unwrap().into_raw() +/// Load c-style string from `const char *` pointer. +#[inline] +unsafe fn load_c_string(ptr: *const c_char) -> String { + CString::from(CStr::from_ptr(ptr)) + .into_string() + .unwrap() } -unsafe fn load_c_string(ptr: *const c_char) -> String { // load string from c-style ptr - String::from( - CStr::from_ptr(ptr).to_str().unwrap() - ) +/// Export c-style string as `const char *` pointer. +/// # NOTE +/// The exported string cannot be freed by the c language `free(void *)` function, +/// but should use the `free_rust_string` callback function, if this interface is +/// not called, a memory leak will occur. +#[inline] +fn export_c_string(string: String) -> *const c_char { + CString::new(string).unwrap().into_raw() } +/// Free the exported c-style string. #[no_mangle] -pub unsafe extern "C" fn free_rust_string(ptr: *const c_char) { // free string memory - let _ = CString::from_raw(ptr as *mut _); +pub unsafe extern "C" fn free_rust_string(ptr: *const c_char) { + let _ = CString::from_raw(ptr as *mut _); // reclaim rust ownership +} + +/// Deserialize text content and serialize to JSON format. +fn json_format(content: &str) -> Option { + let result = match parser(&content) { + Ok(value) => match value { + Value::JSON(json) => serde_json::to_string(&json), + Value::YAML(yaml) => serde_json::to_string(&yaml), + Value::TOML(toml) => serde_json::to_string(&toml), + }, + _ => return None, + }; + match result { + Ok(data) => Some(data), + Err(_) => None, + } } +/// Format the input text into JSON format and return a c-style string, or return +/// `NULL` if an error occurs. #[no_mangle] -pub unsafe extern "C" fn to_json_ffi(content: *const c_char) -> *const c_char { +pub unsafe extern "C" fn to_json(content: *const c_char) -> *const c_char { let content = load_c_string(content); - let result = match to_json(&content) { // convert to JSON format - Some(data) => data, - None => String::new(), // convert failed -> empty string - }; - to_c_string(result) // return c-style ptr + match json_format(&content) { + Some(data) => export_c_string(data), + None => std::ptr::null(), + } +} + +#[cfg(test)] +mod tests { + use super::json_format; + + const JSON_TEST_STR: &str = r#" +{ + "int": 123, + "bool": true, + "float": 3.141592, + "string": "json test", + "array": [1, 2, 3, 4, 5], + "object": { + "sub": "test" + } +} +"#; + + const YAML_TEST_STR: &str = r#" +int: 123 +bool: true +float: 3.141592 +string: "json test" +array: + - 1 + - 2 + - 3 + - 4 + - 5 +object: + sub: test +"#; + + const TOML_TEST_STR: &str = r#" +int = 123 +bool = true +float = 3.141592 +string = "json test" +array = [ 1, 2, 3, 4, 5 ] + +[object] +sub = "test" +"#; + + #[inline] + fn format(raw: &str) -> String { + match json_format(raw) { + Some(data) => data, + None => panic!("format error"), + } + } + + #[test] + fn json_input() { + assert_eq!( + format(JSON_TEST_STR), + format(&json_format(JSON_TEST_STR).unwrap()), + ); + } + + #[test] + fn yaml_input() { + assert_eq!( + format(JSON_TEST_STR), + format(&json_format(YAML_TEST_STR).unwrap()), + ); + } + + #[test] + fn toml_input() { + assert_eq!( + format(JSON_TEST_STR), + format(&json_format(TOML_TEST_STR).unwrap()), + ); + } } diff --git a/src/to-json/src/json.rs b/src/to-json/src/json.rs deleted file mode 100644 index 8f79d44..0000000 --- a/src/to-json/src/json.rs +++ /dev/null @@ -1,21 +0,0 @@ -use serde_json as json; -use crate::parser::{parser, Value}; - -fn json_convert(content: &str) -> Result { // convert to JSON format - let data = match parser(content)? { - Value::JSON(_json) => json::to_string(&_json), - Value::YAML(_yaml) => json::to_string(&_yaml), - Value::TOML(_toml) => json::to_string(&_toml), - }; - match data { - Ok(data) => Ok(data), - Err(err) => Err(err.to_string()), - } -} - -pub fn to_json(content: &str) -> Option { // to JSON string - match json_convert(content) { - Ok(data) => Some(data), - Err(_) => None, // convert failed - } -} diff --git a/src/to-json/src/lib.rs b/src/to-json/src/lib.rs index d5af57d..b8ea04a 100644 --- a/src/to-json/src/lib.rs +++ b/src/to-json/src/lib.rs @@ -1,4 +1,2 @@ mod ffi; -mod json; -mod tests; mod parser; diff --git a/src/to-json/src/parser.rs b/src/to-json/src/parser.rs index 1d84d18..1adc7c3 100644 --- a/src/to-json/src/parser.rs +++ b/src/to-json/src/parser.rs @@ -8,36 +8,88 @@ pub enum Value { TOML(toml::Value), } -fn json_parser(content: &str) -> Option { // parse json content +/// Deserialize text content into JSON format. +fn json_parser(content: &str) -> Option { match json::from_str::(content) { Ok(result) => Some(result), Err(_) => None, } } -fn yaml_parser(content: &str) -> Option { // parse yaml content +/// Deserialize text content into YAML format. +fn yaml_parser(content: &str) -> Option { match yaml::from_str::(content) { Ok(result) => Some(result), Err(_) => None, } } -fn toml_parser(content: &str) -> Option { // parse toml content +/// Deserialize text content into TOML format. +fn toml_parser(content: &str) -> Option { match toml::from_str::(content) { Ok(result) => Some(result), Err(_) => None, } } -pub fn parser(content: &str) -> Result { +/// Try to deserialize the text in JSON, TOML and YAML format. +pub fn parser(content: &str) -> Result { match json_parser(content) { // try JSON format Some(data) => Ok(Value::JSON(data)), None => match toml_parser(content) { // try TOML format Some(data) => Ok(Value::TOML(data)), None => match yaml_parser(content) { // try YAML format Some(data) => Ok(Value::YAML(data)), - None => Err(String::from("unknown input format")), + None => Err("unknown input format"), } } } } + +#[cfg(test)] +mod tests { + use super::Value; + use super::parser; + use super::json_parser; + use super::yaml_parser; + use super::toml_parser; + + const JSON_STR: &str = "{\"test\": \"ok\"}"; + const YAML_STR: &str = "test: ok"; + const TOML_STR: &str = "test = \"ok\""; + + #[test] + fn json() { + assert!(json_parser("").is_none()); // parse invalid text + assert!(json_parser(JSON_STR).is_some()); + } + + #[test] + fn yaml() { + assert!(yaml_parser("").is_none()); // parse invalid text + assert!(yaml_parser(YAML_STR).is_some()); + } + + #[test] + fn toml() { + assert!(toml_parser(".").is_none()); // parse invalid text + assert!(toml_parser(TOML_STR).is_some()); + } + + #[test] + fn global() { + match parser(JSON_STR).unwrap() { + Value::JSON(_) => (), + _ => panic!("JSON parser error"), + }; + match parser(YAML_STR).unwrap() { + Value::YAML(_) => (), + _ => panic!("YAML parser error"), + }; + match parser(TOML_STR).unwrap() { + Value::TOML(_) => (), + _ => panic!("TOML parser error"), + }; + assert!(parser("\0").is_err()); // parse invalid text + } +} diff --git a/src/to-json/src/tests.rs b/src/to-json/src/tests.rs deleted file mode 100644 index 3c832c9..0000000 --- a/src/to-json/src/tests.rs +++ /dev/null @@ -1,80 +0,0 @@ -use crate::json::to_json; - -#[allow(dead_code)] -const JSON_TEST_CONTENT: &str = r#" -{ - "int": 123, - "bool": true, - "float": 3.141592, - "string": "json test", - "array": [1, 2, 3, 4, 5], - "object": { - "sub": "test" - } -} -"#; - -#[allow(dead_code)] -const YAML_TEST_CONTENT: &str = r#" -int: 123 -bool: true -float: 3.141592 -string: "json test" -array: - - 1 - - 2 - - 3 - - 4 - - 5 -object: - sub: test -"#; - -#[allow(dead_code)] -const TOML_TEST_CONTENT: &str = r#" -int = 123 -bool = true -float = 3.141592 -string = "json test" -array = [ 1, 2, 3, 4, 5 ] - -[object] -sub = "test" -"#; - - -mod tests { - use super::*; - - #[allow(dead_code)] - fn format_json(raw: &str) -> String { - match to_json(raw) { - Some(data) => data, - None => panic!("JSON format error"), - } - } - - #[test] - fn json_to_json() { - assert_eq!( - format_json(JSON_TEST_CONTENT), - format_json(&to_json(JSON_TEST_CONTENT).unwrap()), - ); - } - - #[test] - fn yaml_to_json() { - assert_eq!( - format_json(JSON_TEST_CONTENT), - format_json(&to_json(YAML_TEST_CONTENT).unwrap()), - ); - } - - #[test] - fn toml_to_json() { - assert_eq!( - format_json(JSON_TEST_CONTENT), - format_json(&to_json(TOML_TEST_CONTENT).unwrap()), - ); - } -} diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index bb1d68d..23ebb99 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -1,3 +1,4 @@ cmake_minimum_required(VERSION 2.8.12) add_library(utils cJSON.c assets.c logger.c process.c) +target_link_libraries(utils assets ssl crypto) diff --git a/src/utils/assets.c b/src/utils/assets.c index 9f31f42..e415db8 100644 --- a/src/utils/assets.c +++ b/src/utils/assets.c @@ -1,62 +1,106 @@ #include #include #include +#include "assets.h" +#include "loader.h" #include "logger.h" #include "sundry.h" #include "system.h" #include "constant.h" #include "structure.h" -#include "assets.h" -assets update; +asset **update_info; -void assets_update(); -void assets_dump(assets *info); +char **custom_gfwlist; +char **custom_china_ip; +char **custom_chinalist; + +void assets_update_entry(); void extract(const char *file); -void assets_free(assets *info) { // free assets mapping - string_list_free(info->update_file); - string_list_free(info->update_url); - free(info); +asset* asset_init(const char *name) { // init asset item + asset *res = (asset *)malloc(sizeof(asset)); + res->file = strdup(name); + res->sources = string_list_init(); // with multi sources + return res; } -assets* assets_init() { // init assets mapping - assets *info = (assets *)malloc(sizeof(assets)); - info->update_file = string_list_init(); - info->update_url = string_list_init(); - return info; +asset** assets_init() { // init assets list + asset **asset_list = (asset **)malloc(sizeof(asset *)); + *asset_list = NULL; // list end sign + return asset_list; } -void assets_dump(assets *info) { // show assets mapping in debug log - for (char **file = info->update_file; *file != NULL; ++file) { - char **url = file - info->update_file + info->update_url; - log_info("Asset `%s` -> %s", *file, *url); +void assets_free(asset **asset_list) { // free assets list + for (asset **res = asset_list; *res != NULL; ++res) { + string_list_free((*res)->sources); + free((*res)->file); + free(*res); } + free(asset_list); } -void assets_load(assets *info) { // load assets mapping - update.update_file = string_list_init(); - update.update_url = string_list_init(); - string_list_update(&update.update_file, info->update_file); - string_list_update(&update.update_url, info->update_url); - signal(SIGALRM, assets_update); // receive SIGALRM signal - assets_dump(&update); +uint32_t assets_size(asset **asset_list) { // get size of assets list + uint32_t num = 0; + while(asset_list[num++] != NULL); // get list size + return num - 1; } -void assets_update() { // update all assets - if (!string_list_len(update.update_file)) { // empty assets mapping +void assets_dump(asset **asset_list) { // dump assets list content into debug log + for (asset **res = asset_list; *res != NULL; ++res) { // iterate over each item + char *sources = string_list_dump((*res)->sources); + log_debug("Asset item `%s` -> %s", (*res)->file, sources); + free(sources); + } +} + +void assets_append(asset ***asset_list, asset *res) { // push asset item for assets list + uint32_t len = assets_size(*asset_list); + *asset_list = (asset **)realloc(*asset_list, sizeof(asset *) * (len + 2)); // extend asset list + (*asset_list)[len] = res; + (*asset_list)[len + 1] = NULL; // list end sign +} + +void assets_load(asset **info) { // load assets list + update_info = assets_init(); + for (asset **res = info; *res != NULL; ++res) { + assets_append(&update_info, *res); // pointer movement + } + *info = NULL; // disable old assets list + assets_dump(update_info); + log_info("Remote assets load success"); + signal(SIGALRM, assets_update_entry); // receive SIGALRM signal +} + +void assets_update_entry() { // receive SIGALRM for update all assets + if (assets_size(update_info) == 0) { // empty assets list log_info("Skip update assets"); return; } - log_info("Start assets update"); - for (char **file = update.update_file; *file != NULL; ++file) { - char **url = file - update.update_file + update.update_url; - char *asset_file = string_join(ASSETS_DIR, *file); - log_info("Update asset `%s` -> %s", asset_file, *url); - download_file(asset_file, *url); // download asset from url - free(asset_file); + log_info("Start updating assets"); + for (asset **res = update_info; *res != NULL; ++res) { + char *content = string_list_dump((*res)->sources); + log_debug("Updating `%s` -> %s", (*res)->file, content); + if (asset_update((*res)->file, (*res)->sources, ASSETS_DIR)) { + log_debug("Asset `%s` update success", (*res)->file); + } else { + log_warn("Asset `%s` update failed", (*res)->file); + } + free(content); } - log_info("Restart overture"); + + char *gfwlist = string_join(WORK_DIR, ASSET_GFW_LIST); + char *china_ip = string_join(WORK_DIR, ASSET_CHINA_IP); + char *chinalist = string_join(WORK_DIR, ASSET_CHINA_LIST); + save_string_list(gfwlist, custom_gfwlist); + save_string_list(china_ip, custom_china_ip); + save_string_list(chinalist, custom_chinalist); + free(chinalist); + free(china_ip); + free(gfwlist); + load_diverter_assets(); // load assets data into `WORK_DIR` + + log_info("Restart overture to apply new assets"); run_command("pgrep overture | xargs kill"); // restart overture log_info("Assets update complete"); } diff --git a/src/utils/process.c b/src/utils/process.c index f4c2ed4..7ee110c 100644 --- a/src/utils/process.c +++ b/src/utils/process.c @@ -55,10 +55,17 @@ void process_exec(process *proc) { log_perror("%s fork error -> ", proc->name); server_exit(EXIT_FORK_ERROR); } else if (pid == 0) { // child process + log_debug("Subprocess fork success -> PID = %d", getpid()); if (chdir(proc->cwd)) { // change working directory log_perror("%s with invalid cwd `%s` -> ", proc->name, proc->cwd); exit(EXIT_EXEC_ERROR); } + pid_t sid = setsid(); // create new session -> detach current terminal + if (sid == -1) { // session create failed + log_warn("Subprocess failed to create new session"); + } else { + log_debug("Subprocess at new session -> SID = %d", sid); + } prctl(PR_SET_PDEATHSIG, SIGKILL); // child process die with father process if (execvpe(*(proc->cmd), proc->cmd, proc->env) < 0) { log_perror("%s exec error -> ", proc->name); @@ -152,7 +159,7 @@ void get_sub_exit() { // catch child process exit return; } int status; - log_debug("Handle SIGCHLD start"); + log_debug("Handle SIGCHLD begin"); for (process **proc = process_list; *proc != NULL; ++proc) { if ((*proc)->pid == 0) { continue; // skip not running process @@ -177,7 +184,7 @@ void get_sub_exit() { // catch child process exit server_exit(EXIT_WAIT_ERROR); } else if (wait_ret) { // process exit char *exit_msg = get_exit_msg(status); - log_debug("Sub-process (PID = %d) -> %s", wait_ret, exit_msg); + log_debug("Subprocess (PID = %d) -> %s", wait_ret, exit_msg); free(exit_msg); } log_debug("Handle SIGCHLD complete");