diff --git a/proxy/include/proxy/proxy_server.hpp b/proxy/include/proxy/proxy_server.hpp index 0d057f042..750d1e6ee 100644 --- a/proxy/include/proxy/proxy_server.hpp +++ b/proxy/include/proxy/proxy_server.hpp @@ -91,6 +91,7 @@ #include "proxy/default_cert.hpp" #include "proxy/fileop.hpp" #include "proxy/strutil.hpp" +#include "proxy/ipip.hpp" #include "proxy/socks_enums.hpp" #include "proxy/socks_client.hpp" @@ -269,6 +270,18 @@ R"x*x*x( using auth_users = std::tuple; std::vector auth_users_; + // allow_regions/deny_regions 用于指定允许/拒绝的地区, 例如: + // allow_regions_ = { "中国", "香港", "台湾" }; + // deny_regions_ = { "美国", "日本" }; + // allow_regions/deny_regions 为空时, 表示不限制地区. + // 必须在设置了 ipip 数据库文件后才能生效. + std::vector allow_regions_; + std::vector deny_regions_; + + // ipip 数据库文件, 用于指定 ipip 数据库文件, 用于地区限制. + // ipip 数据库文件可以从: https://www.ipip.net 下载. + std::string ipip_db_; + // 多层代理, 当前服务器级连下一个服务器, 对于 client 而言是无感的, // 这是当前服务器通过 proxy_pass_ 指定的下一个代理服务器, 为 client // 实现多层代理. @@ -4072,6 +4085,13 @@ R"x*x*x( boost::system::error_code ec; + if (fs::exists(m_option.ipip_db_, ec)) + { + m_ipip = std::make_unique(); + if (!m_ipip->load(m_option.ipip_db_)) + m_ipip.reset(); + } + m_acceptor.open(endp.protocol(), ec); if (ec) { @@ -4328,11 +4348,38 @@ R"x*x*x( auto client = endp.address().to_string(); client += ":" + std::to_string(endp.port()); + std::vector local_info; + + if (m_ipip) + { + auto [ret, isp] = m_ipip->lookup(endp.address()); + if (!ret.empty()) + { + for (auto& c : ret) + client += " " + c; + + local_info = ret; + } + + if (!isp.empty()) + client += " " + isp; + } + XLOG_DBG << "connection id: " << connection_id << ", start client incoming: " << client; + if (!region_filter(local_info)) + { + XLOG_WARN << "connection id: " + << connection_id + << ", region filter: " + << client; + + continue; + } + socket.set_option(keep_alive_opt, error); // 是否启用透明代理. @@ -4490,6 +4537,55 @@ R"x*x*x( } } + bool region_filter(const std::vector& local_info) const noexcept + { + auto& deny_region = m_option.deny_regions_; + auto& allow_region = m_option.allow_regions_; + + std::optional allow; + + if (m_ipip && (!allow_region.empty() || !deny_region.empty())) + { + for (auto& region : allow_region) + { + for (auto& l : local_info) + { + if (l.starts_with(region)) + { + allow.emplace(true); + break; + } + } + + if (allow) + break; + } + + if (!allow) + { + for (auto& region : deny_region) + { + for (auto& l : local_info) + { + if (l.starts_with(region)) + { + allow.emplace(false); + break; + } + } + + if (allow) + break; + } + } + } + + if (!allow) + return true; + + return *allow; + } + private: // m_executor 保存当前 io_context 的 executor. net::any_io_executor m_executor; @@ -4503,6 +4599,9 @@ R"x*x*x( // 当前机器的所有 ip 地址. std::set m_local_addrs; + // ipip 用于获取 ip 地址的地理位置信息. + std::unique_ptr m_ipip; + using proxy_session_weak_ptr = std::weak_ptr; diff --git a/server/proxy_server/main.cpp b/server/proxy_server/main.cpp index 72e9016dd..712637b34 100644 --- a/server/proxy_server/main.cpp +++ b/server/proxy_server/main.cpp @@ -28,6 +28,7 @@ namespace fs = std::filesystem; #include "proxy/logging.hpp" #include "proxy/use_awaitable.hpp" +#include "proxy/ipip.hpp" #include "main.hpp" @@ -45,6 +46,10 @@ using server_ptr = std::shared_ptr; std::vector auth_users; +std::vector deny_region; +std::vector allow_region; + +std::string ipip_db; std::string doc_dir; std::string log_dir; std::string local_ip; @@ -127,6 +132,10 @@ start_proxy_server(net::io_context& ioc, server_ptr& server) opt.noise_length_ = noise_length; opt.local_ip_ = local_ip; + opt.ipip_db_ = ipip_db; + opt.deny_regions_ = deny_region; + opt.allow_regions_ = allow_region; + opt.reuse_port_ = reuse_port; opt.happyeyeballs_ = happyeyeballs; opt.connect_v4_only_ = connect_v4only; @@ -257,6 +266,9 @@ int main(int argc, char** argv) ("auth_users", po::value>(&auth_users)->multitoken()->default_value(std::vector{"jack:1111"}), "List of authorized users(default user: jack:1111) (e.g: user1:passwd1 user2:passwd2).") + ("allow_region", po::value>(&allow_region)->multitoken(), "Allow region (e.g: 北京|河南|武汉).") + ("deny_region", po::value>(&deny_region)->multitoken(), "Deny region (e.g: 广东|上海|山东).") + ("proxy_pass", po::value(&proxy_pass)->default_value("")->value_name(""), "Specify next proxy pass (e.g: socks5://user:passwd@ip:port).") ("proxy_pass_ssl", po::value(&proxy_pass_ssl)->default_value(false, "false")->value_name(""), "Enable SSL for the next proxy pass.") @@ -271,6 +283,7 @@ int main(int argc, char** argv) ("ssl_ciphers", po::value(&ssl_ciphers)->value_name("ssl_ciphers"), "Specify enabled SSL ciphers") ("ssl_prefer_server_ciphers", po::value(&ssl_prefer_server_ciphers)->default_value(false, "false")->value_name(""), "Prefer server ciphers over client ciphers for SSLv3 and TLS protocols.") + ("ipip_db", po::value(&ipip_db)->value_name("")->default_value("17monipdb.datx"), "Specify ipip database filename.") ("http_doc", po::value(&doc_dir)->value_name("doc"), "Specify document root directory for HTTP server.") ("autoindex", po::value(&autoindex)->default_value(false), "Enable directory listing.") ("logs_path", po::value(&log_dir)->value_name(""), "Specify directory for log files.")