diff --git a/CMakeLists.txt b/CMakeLists.txt index e981867..6e290be 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,10 +26,10 @@ add_library(jsonxx STATIC third_party/jsonxx/jsonxx.cc) include_directories("third_party/curi/src") add_subdirectory(third_party/curi/src) -add_executable(ahpc src/http_proxy_client_main.cpp src/http_proxy_client.cpp src/http_proxy_client_config.cpp src/http_proxy_client_connection.cpp) +add_executable(ahpc src/http_proxy_client_main.cpp src/http_proxy_client.cpp src/http_proxy_client_config.cpp src/http_proxy_client_connection.cpp src/hash_utils.cpp) target_link_libraries(ahpc ${OPENSSL_LIBRARIES} jsonxx) -add_executable(ahps src/http_proxy_server_main.cpp src/http_proxy_server.cpp src/http_proxy_server_config.cpp src/http_proxy_server_connection.cpp src/http_header_parser.cpp src/base64.cpp src/authentication.cpp) +add_executable(ahps src/http_proxy_server_main.cpp src/http_proxy_server.cpp src/http_proxy_server_config.cpp src/http_proxy_server_connection.cpp src/http_header_parser.cpp src/hash_utils.cpp src/authentication.cpp) target_link_libraries(ahps ${OPENSSL_LIBRARIES} jsonxx curi) if(UNIX) diff --git a/README.md b/README.md index 41d00c3..7a91134 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ AHP(Azure Http Proxy)是一款高速、安全、轻量级和跨平台的HTTP代 - 对目标域名的解析在服务端进行,可以解决本地DNS污染的问题 - 服务端同时支持多种数据加密方式,数据加密方式可由客户端任意指定,客户端可以权衡机器性能以及安全需求选择合适的加密方式 - 多线程并发处理,充分利用多处理器的优势,能同时处理成千上万的并发连接 - - 多用户支持,允许为每个用户使用独立的帐号和密码 + - 多用户支持,允许为每个用户使用独立的auth_key `(1.1及以上版本)` ## 编译和安装 @@ -24,7 +24,7 @@ AHP使用了部分C++17特性,所以对编译器的版本有较高要求,下 ### 安装依赖 - - OpenSSL + - OpenSSL >= 3.0 #### Linux @@ -56,7 +56,6 @@ AHP使用自动化构建工具CMake来实现跨平台构建 - CMake >= 2.8 -Windows下可以使用cmake-gui.exe,Linux或其他类Unix系统可以使用下面的命令编译 ```shell $ cd azure-http-proxy $ mkdir build @@ -94,15 +93,10 @@ $ openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem "timeout": 240, "workers": 4, "auth": true, - "users": [ - { - "username": "username1", - "password": "password1" - }, - { - "username": "foobar", - "password": "bazqux" - } + "auth_key_list": [ + "testing_key", + "Bob", + "Alice" ] } ``` @@ -111,11 +105,11 @@ $ openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem ----------------|--------------------|------------------|-----------| bind_address | 服务端绑定的IP地址 | 否 | "0.0.0.0" | listen_port | 服务端绑定的端口 | 否 | 8090 | -rsa_private_key | RSA私钥 | 是 | 无 | +rsa_private_key | RSA私钥 | 是 | 无 | timeout | 超时时间(秒) | 否 | 240 | workers | 并发工作线程数 | 否 | 4 | auth | 启用代理身份验证 | 否 | false | -users | 用户列表 | auth为true时必选 | 无 | +auth_key_list | auth_key列表 | auth为true时必选 | 无 | ### 配置客户端 @@ -129,7 +123,8 @@ users | 用户列表 | auth为true时必选 | 无 | "rsa_public_key": "-----BEGIN PUBLIC KEY----- ...... -----END PUBLIC KEY-----", "cipher": "aes-256-cfb", "timeout": 240, - "workers": 2 + "workers": 2, + "auth_key": "testing_key" } ``` @@ -143,6 +138,7 @@ rsa_public_key | RSA公钥 | 是 | 无 cipher | 加密方法 | 否 | "aes-256-cfb" | timeout | 超时时间(秒) | 否 | 240 | workers | 并发工作线程数 | 否 | 2 | +auth_key | 用于身份验证的字符串 | 否 | 值为空字符串或没有这个字段时,请求不携带auth_key,仅当server的auth为false时才能成功建立连接| #### 支持的加密方法 diff --git a/example/client.json b/example/client.json index 0df6515..632ba13 100755 --- a/example/client.json +++ b/example/client.json @@ -6,5 +6,6 @@ "rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPbPBU61RYBI0rUDVso+\nTzkQ7bXO1j4GWxbYZ3nEL6sLbrftv7rpYq5uPLi9DdJ3ZoEUjxlnO+VUOOtm7LpR\nGmWqUQdNnYHuiZU1UuH7pDIXejQwwSC698FB1kwnoxV4LICkiA1a4qucqlnG8nN6\ngBFs3/1K2DuUs0Hg1hZKlkOq/ONR82XGhXkB/HVwmfgQlZpVbWHQDsZiOv1SUnQW\n8Zs6E/JmW6llBkWtsQT9nQ2uzcV1JGzV0ltB4N0CMC8u2zv/LLTSgS4IKrVicAqO\n9TWkGOFmGowV7PpEAEQC1WcBXThLpUYk2QqiSvTTLTdFNmwEH+hKa1ZBPqOcaTA1\ndQIDAQAB\n-----END PUBLIC KEY-----", "cipher": "aes-256-cfb", "timeout": 240, - "workers": 2 + "workers": 2, + "auth_key": "testing_key" } diff --git a/example/server.json b/example/server.json index 7a9e5ba..38b2f2e 100755 --- a/example/server.json +++ b/example/server.json @@ -5,14 +5,11 @@ "timeout": 240, "workers": 4, "auth": true, - "users": [ - { - "username": "username1", - "password": "password1" - }, - { - "username": "foobar", - "password": "bazqux" - } + "auth_key_list": [ + "testing_key", + "Bob", + "Alice", + "+ZI1w$u9N65lTw*nL@$", + "SoHPa4xNMBWoXxSOp+6snUtqtdXFH(MO" ] } diff --git a/src/authentication.cpp b/src/authentication.cpp index 4fe657d..5a08aa1 100755 --- a/src/authentication.cpp +++ b/src/authentication.cpp @@ -9,7 +9,7 @@ #include #include "authentication.hpp" -#include "base64.hpp" +#include "hash_utils.hpp" namespace azure_proxy { @@ -17,46 +17,20 @@ authentication::authentication() { } -auth_result authentication::auth_basic(const std::string::const_iterator begin, const std::string::const_iterator end) const +bool authentication::auth(const auth_key_hash_t& auth_key_hash) const { - std::string authorization; - try { - azure_proxy::encoding::base64_decode(begin, end, std::back_inserter(authorization)); - } - catch (const azure_proxy::encoding::decode_base64_error&) { - return auth_result::error; - } - auto colon_pos = authorization.find(':'); - if (colon_pos == std::string::npos) { - return auth_result::error; - } - std::string username(authorization.begin(), authorization.begin() + colon_pos); - std::string password(authorization.begin() + colon_pos + 1, authorization.end()); - auto iter = this->users_map.find(username); - if (iter != this->users_map.end() && std::get<1>(*iter) == password) { - return auth_result::ok; - } - return auth_result::incorrect; + return this->auth_keys_map.find(auth_key_hash) != this->auth_keys_map.end(); } -auth_result authentication::auth(const std::string& value) const +void authentication::add_auth_key(const std::string& auth_key) { - if (value.size() > 6 && std::equal(value.begin(), value.begin() + 6, "Basic ")) { - return this->auth_basic(value.begin() + 6, value.end()); - } - else { - return auth_result::error; - } + auto auth_key_hash = hash_utils::sha256(reinterpret_cast(auth_key.data()), auth_key.size()); + this->auth_keys_map[auth_key_hash] = auth_key; } -void authentication::add_user(const std::string& username, const std::string& password) +void authentication::remove_all_auth_keys() { - this->users_map[username] = password; -} - -void authentication::remove_all_users() -{ - this->users_map.clear(); + this->auth_keys_map.clear(); } authentication& authentication::get_instance() diff --git a/src/authentication.hpp b/src/authentication.hpp index fcf9075..bb8af86 100755 --- a/src/authentication.hpp +++ b/src/authentication.hpp @@ -8,26 +8,22 @@ #ifndef AZURE_AUTHENTICATION_HPP #define AZURE_AUTHENTICATION_HPP +#include #include #include namespace azure_proxy { -enum class auth_result { - ok, - incorrect, - error -}; +using auth_key_hash_t = std::array; class authentication { - std::map users_map; + std::map auth_keys_map; private: authentication(); - auth_result auth_basic(const std::string::const_iterator begin, const std::string::const_iterator end) const; public: - auth_result auth(const std::string& value) const; - void add_user(const std::string& username, const std::string& password); - void remove_all_users(); + bool auth(const auth_key_hash_t& auth_key_hash) const; + void add_auth_key(const std::string& auth_key); + void remove_all_auth_keys(); static authentication& get_instance(); }; diff --git a/src/base64.cpp b/src/base64.cpp deleted file mode 100755 index 58570b7..0000000 --- a/src/base64.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * base64.cpp: - * - * Copyright (C) 2015-2023 Light Lin All Rights Reserved. - * - */ - -#include "base64.hpp" - -namespace azure_proxy { -namespace encoding { - -const char base64_encode_table[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', //0~6 - 'H', 'I', 'J', 'K', 'L', 'M', 'N', //7~13 - 'O', 'P', 'Q', /**/ 'R', 'S', 'T', //14~19 - 'U', 'V', 'W', /**/ 'X', 'Y', 'Z', //21~25 - 'a', 'b', 'c', 'd', 'e', 'f', 'g', //26~32 - 'h', 'i', 'j', 'k', 'l', 'm', 'n', //33~39 - 'o', 'p', 'q', /**/ 'r', 's', 't', //40~45 - 'u', 'v', 'w', /**/ 'x', 'y', 'z', //46~51 - '0', '1', '2', '3', '4', '5', '6', //52~58 - '7', '8', '9', '+', '/' //59~63 -}; - -const int base64_decode_table[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, - -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, -1, -1, -1, -1, -1 -}; - -} // namespace encoding -} // namespace azure_proxy diff --git a/src/base64.hpp b/src/base64.hpp deleted file mode 100755 index 4a22e16..0000000 --- a/src/base64.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * base64.hpp: - * - * Copyright (C) 2015-2023 Light Lin All Rights Reserved. - * - */ - -#ifndef AZURE_ENCODING_BASE64_HPP -#define AZURE_ENCODING_BASE64_HPP -#include -#include -#include - -namespace azure_proxy { -namespace encoding { - -class decode_base64_error : public std::exception { - const char* _msg; -public: - explicit decode_base64_error(const char* msg) : _msg(msg) {} - const char* what() const throw() { - return this->_msg; - } - ~decode_base64_error() throw() { - } -}; - -extern const char base64_encode_table[64]; - -template -OutputIterator base64_encode(InputIterator begin, InputIterator end, OutputIterator out) -{ - typedef unsigned char byte_t; - static_assert(sizeof(typename std::iterator_traits::value_type) == sizeof(byte_t), "error"); - auto iter = begin; - while (iter != end) { - byte_t byte0 = static_cast(*iter++); - if (iter == end) { - *out = base64_encode_table[byte0 >> 2]; - *out = base64_encode_table[static_cast(byte0 & 0x03) << 4]; - *out = '='; - *out = '='; - break; - } - byte_t byte1 = static_cast(*iter++); - if (iter == end) { - *out = base64_encode_table[byte0 >> 2]; - *out = base64_encode_table[static_cast(byte0 & 0x03) << 4 | static_cast(byte1 >> 4)]; - *out = base64_encode_table[static_cast(byte1 & 0x0f) << 2]; - *out = '='; - break; - } - byte_t byte2 = *iter++; - *out = base64_encode_table[byte0 >> 2]; - *out = base64_encode_table[static_cast(byte0 & 0x03) << 4 | static_cast(byte1 >> 4)]; - *out = base64_encode_table[static_cast(byte1 & 0x0f) << 2 | static_cast(byte2 >> 6)]; - *out = base64_encode_table[byte2 & 0x3f]; - } - return out; -} - -extern const int base64_decode_table[128]; - -template -OutputIterator base64_decode(InputIterator begin, InputIterator end, OutputIterator out) { - static_assert(std::is_same::value_type, char>::value, "error"); - typedef unsigned char byte_t; - auto iter = begin; - while (iter != end) { - char char0 = *iter++; - char char1 = iter != end ? *iter++ : throw decode_base64_error("invalid length"); - char char2 = iter != end ? *iter++ : throw decode_base64_error("invalid length"); - char char3 = iter != end ? *iter++ : throw decode_base64_error("invalid length"); - byte_t _byte; - if (char0 < '\0' || char0 == '=' || base64_decode_table[char0] == -1) { - throw decode_base64_error("failed to decode"); - } - _byte = static_cast(base64_decode_table[char0]) << 2; - if (char1 < '\0' || char1 == '=' || base64_decode_table[char1] == -1) { - throw decode_base64_error("failed to decode"); - } - *out = static_cast(_byte | static_cast(base64_decode_table[char1]) >> 4); - _byte = static_cast(static_cast(base64_decode_table[char1]) << 4); - if (iter == end && char2 == '=' && char3 == '=') { - break; - } - else if (char2 < '\0' || base64_decode_table[char2] == -1) { - throw decode_base64_error("failed to decode"); - } - *out = static_cast(_byte | static_cast(base64_decode_table[char2]) >> 2); - _byte = static_cast(static_cast(base64_decode_table[char2]) << 6); - if (iter == end && char3 == '=') { - break; - } - else if (char3 < '\0' || base64_decode_table[char3] == -1) { - throw decode_base64_error("failed to decode"); - } - *out = static_cast(_byte | static_cast(base64_decode_table[char3])); - } - return out; -} - -} // namespace encoding -} // namespace azure_proxy - -#endif diff --git a/src/hash_utils.cpp b/src/hash_utils.cpp new file mode 100644 index 0000000..973f050 --- /dev/null +++ b/src/hash_utils.cpp @@ -0,0 +1,21 @@ +/* + * hash_utils.cpp: + * + * Copyright (C) 2023 Light Lin All Rights Reserved. + * + */ + +#include "hash_utils.hpp" +#include + +namespace azure_proxy { +namespace hash_utils { + +std::array sha256(const unsigned char* data, std::size_t count) { + std::array result; + SHA256(data, count, result.data()); + return result; +} + +} // namespace hash_utils +} // namespace azure_proxy diff --git a/src/hash_utils.hpp b/src/hash_utils.hpp new file mode 100644 index 0000000..c03c954 --- /dev/null +++ b/src/hash_utils.hpp @@ -0,0 +1,21 @@ +/* + * hash_utils.hpp: + * + * Copyright (C) 2023 Light Lin All Rights Reserved. + * + */ + +#ifndef AZURE_HASH_UTILS_HPP +#define AZURE_HASH_UTILS_HPP + +#include + +namespace azure_proxy { +namespace hash_utils { + +std::array sha256(const unsigned char* data, std::size_t count); + +} // namespace hash_utils +} // namespace azure_proxy + +#endif // AZURE_HASH_UTILS_HPP diff --git a/src/http_proxy_client_config.cpp b/src/http_proxy_client_config.cpp index d1a95bb..9f4885a 100755 --- a/src/http_proxy_client_config.cpp +++ b/src/http_proxy_client_config.cpp @@ -125,6 +125,11 @@ bool http_proxy_client_config::load_config_data(const std::string& config_data) else { this->config_map["workers"] = 2u; } + std::string auth_key; + if (json_obj.has("auth_key")) { + auth_key = std::string(json_obj.get("auth_key")); + } + this->config_map["auth_key"] = auth_key; rollback = false; return true; @@ -212,6 +217,11 @@ unsigned int http_proxy_client_config::get_workers() const return this->get_config_value("workers"); } +const std::string& http_proxy_client_config::get_auth_key() const +{ + return this->get_config_value("auth_key"); +} + http_proxy_client_config& http_proxy_client_config::get_instance() { static http_proxy_client_config instance; diff --git a/src/http_proxy_client_config.hpp b/src/http_proxy_client_config.hpp index d4bbb9c..e13a02d 100755 --- a/src/http_proxy_client_config.hpp +++ b/src/http_proxy_client_config.hpp @@ -40,6 +40,7 @@ class http_proxy_client_config { const std::string& get_cipher() const; unsigned int get_timeout() const; unsigned int get_workers() const; + const std::string& get_auth_key() const; static http_proxy_client_config& get_instance(); }; diff --git a/src/http_proxy_client_connection.cpp b/src/http_proxy_client_connection.cpp index 4cd93e6..8cc4beb 100755 --- a/src/http_proxy_client_connection.cpp +++ b/src/http_proxy_client_connection.cpp @@ -12,6 +12,7 @@ #include "http_proxy_client_config.hpp" #include "http_proxy_client_connection.hpp" #include "key_generator.hpp" +#include "hash_utils.hpp" namespace azure_proxy { @@ -44,10 +45,18 @@ void http_proxy_client_connection::start() cipher_info_raw[1] = 'H'; cipher_info_raw[2] = 'P'; - // 3 zero - // 4 zero + // 3 protocol version + // - 0: version 1.0 + // - 1: since version 1.1, support 32 bytes auth_key_hash + unsigned char protocol_version = 1; + const auto &auth_key = http_proxy_client_config::get_instance().get_auth_key(); + bool has_auth_key = !auth_key.empty(); + if (!has_auth_key) { + // Use old protocol to be compatible with version 1.0 + protocol_version = 0; + } - // 5 cipher code + // cipher code // 0x00 aes-128-cfb // 0x01 aes-128-cfb8 // 0x02 aes-128-cfb1 @@ -65,11 +74,11 @@ void http_proxy_client_connection::start() // 0x0E aes-256-ctr unsigned char cipher_code = 0; + std::vector ivec(16); + std::vector key_vec; const auto& cipher_name = http_proxy_client_config::get_instance().get_cipher(); if (cipher_name.size() > 7 && std::equal(cipher_name.begin(), cipher_name.begin() + 3, "aes")) { // aes - std::vector ivec(16); - std::vector key_vec; assert(cipher_name[3] == '-' && cipher_name[7] == '-'); if (std::strcmp(cipher_name.c_str() + 8, "cfb") == 0 || std::strcmp(cipher_name.c_str() + 8, "cfb128") == 0) { // aes-xxx-cfb @@ -166,20 +175,41 @@ void http_proxy_client_connection::start() this->encryptor = std::unique_ptr(new aes_ctr128_encryptor(key_vec.data(), key_vec.size() * 8, ivec.data())); this->decryptor = std::unique_ptr(new aes_ctr128_decryptor(key_vec.data(), key_vec.size() * 8, ivec.data())); } - // 7 ~ 22 ivec - // 23 ~ key - std::copy(ivec.cbegin(), ivec.cend(), cipher_info_raw.begin() + 7); - std::copy(key_vec.cbegin(), key_vec.cend(), cipher_info_raw.begin() + 23); } if (!this->encryptor || !this->decryptor) { return; } - // 5 cipher code - cipher_info_raw[5] = static_cast(cipher_code); - - // 6 zero + // 3 protocol version + cipher_info_raw[3] = protocol_version; + if (protocol_version == 0) { + // 4 zero + // 5 cipher code + cipher_info_raw[5] = cipher_code; + // 6 zero + // 7 ~ 22 ivec + std::copy(ivec.cbegin(), ivec.cend(), cipher_info_raw.begin() + 7); + // 23 ~ (38/46/54) cipher key + std::copy(key_vec.cbegin(), key_vec.cend(), cipher_info_raw.begin() + 23); + } else { + // 4 auth type + // - 0 no authentication + // - 1 32 bytes auth_key_hash + unsigned char auth_type = has_auth_key ? 1 : 0; + cipher_info_raw[4] = auth_type; + // 5 cipher code + cipher_info_raw[5] = cipher_code; + // 6 ~ 37 auth_key_hash + if (auth_type == 1) { + auto auth_key_hash = hash_utils::sha256(reinterpret_cast(auth_key.data()), auth_key.size()); + std::copy(auth_key_hash.cbegin(), auth_key_hash.cend(), cipher_info_raw.begin() + 6); + } + // 38 ~ 53 ivec + std::copy(ivec.cbegin(), ivec.cend(), cipher_info_raw.begin() + 38); + // 54 ~ (69/77/85) cipher key + std::copy(key_vec.cbegin(), key_vec.cend(), cipher_info_raw.begin() + 54); + } rsa rsa_pub(http_proxy_client_config::get_instance().get_rsa_public_key()); if (rsa_pub.modulus_size() < 128) { diff --git a/src/http_proxy_server_config.cpp b/src/http_proxy_server_config.cpp index 81d4ff3..c15f274 100755 --- a/src/http_proxy_server_config.cpp +++ b/src/http_proxy_server_config.cpp @@ -33,7 +33,7 @@ bool http_proxy_server_config::load_config_data(const std::string& config_data) std::shared_ptr auto_rollback(&rollback, [this](bool* rollback) { if (*rollback) { this->config_map.clear(); - authentication::get_instance().remove_all_users(); + authentication::get_instance().remove_all_auth_keys(); } }); @@ -85,20 +85,24 @@ bool http_proxy_server_config::load_config_data(const std::string& config_data) else { this->config_map["workers"] = 4u; } - if (json_obj.has("auth")) { - this->config_map["auth"] = json_obj.get("auth"); - if (!json_obj.has("users")) { - std::cerr << "Could not find \"users\" in config or it's value is not a array" << std::endl; + if (json_obj.has("auth") && json_obj.get("auth")) { + this->config_map["auth"] = true; + if (!json_obj.has("auth_key_list")) { + std::cerr << "Could not find \"auth_key_list\" in config or it's value is not a array" << std::endl; return false; } - const jsonxx::Array& users_array = json_obj.get("users"); - for (size_t i = 0; i < users_array.size(); ++i) { - if (!users_array.has(i) || !users_array.get(i).has("username") || !users_array.get(i).has("username")) { - std::cerr << "The value of \"users\" contains unexpected element" << std::endl; + const jsonxx::Array& auth_key_list = json_obj.get("auth_key_list"); + for (size_t i = 0; i < auth_key_list.size(); ++i) { + if (!auth_key_list.has(i)) { + std::cerr << "The value of \"auth_key_list\" contains unexpected element" << std::endl; return false; } - authentication::get_instance().add_user(users_array.get(i).get("username"), - users_array.get(i).get("password")); + const auto &auth_key = auth_key_list.get(i); + if (auth_key.empty()) { + std::cerr << "Ignore empty \"auth_key\" at index: " << i << std::endl; + continue; + } + authentication::get_instance().add_auth_key(auth_key); } } else { diff --git a/src/http_proxy_server_connection.cpp b/src/http_proxy_server_connection.cpp index 2a5911a..4e4c12e 100755 --- a/src/http_proxy_server_connection.cpp +++ b/src/http_proxy_server_connection.cpp @@ -303,32 +303,6 @@ void http_proxy_server_connection::report_error(const std::string& status_code, this->async_write_data_to_proxy_client(this->modified_response_data.data(), 0 ,this->modified_response_data.size()); } -void http_proxy_server_connection::report_authentication_failed() -{ - std::string content = "407 Proxy Authentication Required"; - content += "

407 Proxy Authentication Required


azure http proxy server
"; - this->modified_response_data = "HTTP/1.1 407 Proxy Authentication Required\r\n"; - this->modified_response_data += "Server: AzureHttpProxy\r\n"; - this->modified_response_data += "Proxy-Authenticate: Basic realm=\"AzureHttpProxy\"\r\n"; - this->modified_response_data += "Content-Type: text/html\r\n"; - this->modified_response_data += "Connection: Close\r\n"; - this->modified_response_data += "Content-Length: "; - this->modified_response_data += std::to_string(content.size()); - this->modified_response_data += "\r\n\r\n"; - this->modified_response_data += content; - unsigned char temp_buffer[16]; - for (std::size_t i = 0; i * 16 < this->modified_response_data.size(); ++i) { - std::size_t block_length = 16; - if (this->modified_response_data.size() - i * 16 < 16) { - block_length = this->modified_response_data.size() % 16; - } - this->encryptor->encrypt(reinterpret_cast(&this->modified_response_data[i * 16]), temp_buffer, block_length); - std::copy(temp_buffer, temp_buffer + block_length, reinterpret_cast(&this->modified_response_data[i * 16])); - } - this->connection_context.connection_state = proxy_connection_state::report_error; - this->async_write_data_to_proxy_client(this->modified_response_data.data(), 0, this->modified_response_data.size()); -} - void http_proxy_server_connection::set_timer() { if (this->timer.expires_after(std::chrono::seconds(http_proxy_server_config::get_instance().get_timeout())) != 0) { @@ -419,11 +393,33 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte if (decrypted_cipher_info[0] != 'A' || decrypted_cipher_info[1] != 'H' || - decrypted_cipher_info[2] != 'P' || - decrypted_cipher_info[3] != 0 || - decrypted_cipher_info[4] != 0 || - decrypted_cipher_info[6] != 0 - ) { + decrypted_cipher_info[2] != 'P') { + return; + } + + unsigned char protocol_version = decrypted_cipher_info[3]; + auto need_auth = http_proxy_server_config::get_instance().enable_auth(); + if (protocol_version == 0) { + if (need_auth || decrypted_cipher_info[4] != 0 || decrypted_cipher_info[6] != 0) { + return; + } + } else if (protocol_version == 1) { + if (need_auth) { + // 4 auth type + // - 0 no authentication + // - 1 32 bytes auth_key + auto auth_type = decrypted_cipher_info[4]; + if (auth_type != 1) { + return; + } + // 6 ~ 37 auth_key + std::array auth_key_hash; + std::copy(decrypted_cipher_info.cbegin() + 6, decrypted_cipher_info.cbegin() + 38, auth_key_hash.begin()); + if (!authentication::get_instance().auth(auth_key_hash)) { + return; + } + } + } else { return; } @@ -445,6 +441,8 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte // 0x0D aes-256-ofb // 0x0E aes-256-ctr unsigned char cipher_code = decrypted_cipher_info[5]; + std::size_t ivec_offset = protocol_version == 0 ? 7 : 38; + std::size_t cipher_key_offset = protocol_version == 0 ? 23 : 54; if (cipher_code == '\x00' || cipher_code == '\x05' || cipher_code == '\x0A') { // aes-xxx-cfb std::size_t ivec_size = 16; @@ -457,8 +455,8 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte // aes-192-cfb key_bits = 192; } - this->encryptor = std::unique_ptr(new aes_cfb128_encryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); - this->decryptor = std::unique_ptr(new aes_cfb128_decryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); + this->encryptor = std::unique_ptr(new aes_cfb128_encryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); + this->decryptor = std::unique_ptr(new aes_cfb128_decryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); } else if (cipher_code == '\x01' || cipher_code == '\x06' || cipher_code == '\x0B') { // ase-xxx-cfb8 @@ -472,8 +470,8 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte // aes-192-cfb8 key_bits = 192; } - this->encryptor = std::unique_ptr(new aes_cfb8_encryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); - this->decryptor = std::unique_ptr(new aes_cfb8_decryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); + this->encryptor = std::unique_ptr(new aes_cfb8_encryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); + this->decryptor = std::unique_ptr(new aes_cfb8_decryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); } else if (cipher_code == '\x02' || cipher_code == '\x07' || cipher_code == '\x0C') { // ase-xxx-cfb1 @@ -487,8 +485,8 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte // aes-192-cfb1 key_bits = 192; } - this->encryptor = std::unique_ptr(new aes_cfb1_encryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); - this->decryptor = std::unique_ptr(new aes_cfb1_decryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); + this->encryptor = std::unique_ptr(new aes_cfb1_encryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); + this->decryptor = std::unique_ptr(new aes_cfb1_decryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); } else if (cipher_code == '\x03' || cipher_code == '\x08' || cipher_code == '\x0D') { // ase-xxx-ofb @@ -502,8 +500,8 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte // aes-192-ofb key_bits = 192; } - this->encryptor = std::unique_ptr(new aes_ofb128_encryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); - this->decryptor = std::unique_ptr(new aes_ofb128_decryptor(&decrypted_cipher_info[23], key_bits, &decrypted_cipher_info[7])); + this->encryptor = std::unique_ptr(new aes_ofb128_encryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); + this->decryptor = std::unique_ptr(new aes_ofb128_decryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, &decrypted_cipher_info[ivec_offset])); } else if (cipher_code == '\x04' || cipher_code == '\x09' || cipher_code == '\x0E') { // ase-xxx-ctr @@ -518,8 +516,8 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte key_bits = 192; } std::vector ivec(ivec_size, 0); - this->encryptor = std::unique_ptr(new aes_ctr128_encryptor(&decrypted_cipher_info[23], key_bits, ivec.data())); - this->decryptor = std::unique_ptr(new aes_ctr128_decryptor(&decrypted_cipher_info[23], key_bits, ivec.data())); + this->encryptor = std::unique_ptr(new aes_ctr128_encryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, ivec.data())); + this->decryptor = std::unique_ptr(new aes_ctr128_decryptor(&decrypted_cipher_info[cipher_key_offset], key_bits, ivec.data())); } if (this->encryptor == nullptr || this->decryptor == nullptr) { return; @@ -567,20 +565,6 @@ void http_proxy_server_connection::on_proxy_client_data_arrived(std::size_t byte return; } - if (http_proxy_server_config::get_instance().enable_auth()) { - auto proxy_authorization_value = this->request_header->get_header_value("Proxy-Authorization"); - bool auth_success = false; - if (proxy_authorization_value) { - if (authentication::get_instance().auth(*proxy_authorization_value) == auth_result::ok) { - auth_success = true; - } - } - if (!auth_success) { - this->report_authentication_failed(); - return; - } - } - if (this->request_header->method() == "CONNECT") { this->async_connect_to_origin_server(); return; diff --git a/src/http_proxy_server_connection.hpp b/src/http_proxy_server_connection.hpp index 6c8fc35..60edc75 100755 --- a/src/http_proxy_server_connection.hpp +++ b/src/http_proxy_server_connection.hpp @@ -63,7 +63,6 @@ class http_proxy_server_connection : public std::enable_shared_from_this