Skip to content

Commit

Permalink
common: add configuration validation feature
Browse files Browse the repository at this point in the history
Fixes #1085.
  • Loading branch information
Chilledheart committed Sep 9, 2024
1 parent 7e49c94 commit a8c4284
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 2 deletions.
6 changes: 6 additions & 0 deletions doc/yass_cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ See <https://github.com/Chilledheart/yass/wiki/Usage>.
* `-c` _file_, `--configfile` _file_:
Use specified _file_ as config file.

* `-t`:
Don't run, just test the configuration file.

* `-v`, `--version`:
Print yass_cli version.

* `--limit_rate` _rate_:
Limits the _rate_ of response transmission to a client. Uint can be `(none)`, `k` and `m`.

Expand Down
6 changes: 6 additions & 0 deletions doc/yass_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ See <https://github.com/Chilledheart/yass/wiki/Usage>.
* `-c` _file_, `--configfile` _file_:
Use specified _file_ as config file.

* `-t`:
Don't run, just test the configuration file.

* `-v`, `--version`:
Print yass_server version.

* `--limit_rate` _rate_:
Limits the _rate_ of response transmission to a client. Uint can be `(none)`, `k` and `m`.

Expand Down
10 changes: 10 additions & 0 deletions src/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ int main(int argc, const char* argv[]) {
config::SetClientUsageMessage(exec_path);
config::ReadConfigFileAndArguments(argc, argv);

std::string err = config::ValidateConfig();
if (!err.empty()) {
LOG(WARNING) << "Failed to validate config: " << err;
return -1;
}
if (config::testOnlyMode) {
LOG(WARNING) << "Configuration Validated";
return 0;
}

#ifdef _WIN32
int iResult = 0;
WSADATA wsaData = {0};
Expand Down
89 changes: 87 additions & 2 deletions src/config/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,87 @@ bool SaveConfig() {
return all_fields_written;
}

std::string ValidateConfig() {
std::string err;
std::ostringstream err_msg;

auto server_host = absl::GetFlag(FLAGS_server_host);
auto server_sni = absl::GetFlag(FLAGS_server_sni);
auto server_port = absl::GetFlag(FLAGS_server_port);
auto username = absl::GetFlag(FLAGS_username);
auto password = absl::GetFlag(FLAGS_password);
auto method = absl::GetFlag(FLAGS_method);
auto local_host = absl::GetFlag(FLAGS_local_host);
// auto local_port = absl::GetFlag(FLAGS_local_port);
auto doh_url = absl::GetFlag(FLAGS_doh_url);
auto dot_host = absl::GetFlag(FLAGS_dot_host);
// auto limit_rate = absl::GetFlag(FLAGS_limit_rate);
// auto timeout = absl::GetFlag(FLAGS_connect_timeout);

// TODO validate other configurations as well

if (server_host.empty() || server_host.size() >= TLSEXT_MAXLEN_host_name) {
err_msg << ",Invalid Server Host: " << server_host;
}

if (server_sni.size() >= TLSEXT_MAXLEN_host_name) {
err_msg << ",Invalid Server Host: " << server_sni;
}

if (server_port.port == 0) {
err_msg << ",Invalid Server Port: " << server_port.port;
}

if (method == CRYPTO_INVALID) {
err_msg << ",Invalid Cipher: " << to_cipher_method_str(method);
}

if (method == CRYPTO_SOCKS4 || method == CRYPTO_SOCKS4A) {
if (!username.empty() || !password.empty()) {
err_msg << ",SOCKS4/SOCKSA doesn't support username and passsword";
}
}

if (method == CRYPTO_SOCKS5 || method == CRYPTO_SOCKS5H) {
if (username.empty() ^ password.empty()) {
err_msg << ",SOCKS5/SOCKS5H requires both of username and passsword";
}
}

if (CIPHER_METHOD_IS_HTTP(method)) {
if (username.empty() ^ password.empty()) {
err_msg << ",HTTP requires both of username and passsword";
}
}

if (local_host.empty() || local_host.size() >= TLSEXT_MAXLEN_host_name) {
err_msg << ",Invalid Local Host: " << local_host;
}

if (!doh_url.empty()) {
GURL url(doh_url);
if (!url.is_valid() || !url.has_host() || !url.has_scheme() || url.scheme() != "https") {
err_msg << ",Invalid DoH URL: " << doh_url;
}
if (!dot_host.empty()) {
err_msg << ",Conflicting DoT Host: " << dot_host;
}
}

if (!dot_host.empty()) {
if (dot_host.size() >= TLSEXT_MAXLEN_host_name) {
err_msg << ",Invalid DoT Host: " << dot_host;
}
}

auto ret = err_msg.str();
if (ret.empty()) {
return ret;
} else {
return ret.substr(1);
}
}

std::string ReadConfigFromArgument(std::string_view server_host,
std::string_view server_sni,
std::string_view _server_port,
Expand All @@ -184,7 +265,7 @@ std::string ReadConfigFromArgument(std::string_view server_host,
}

PortFlag server_port;
if (!AbslParseFlag(_server_port, &server_port, &err)) {
if (!AbslParseFlag(_server_port, &server_port, &err) || server_port.port == 0u) {
err_msg << ",Invalid Server Port: " << _server_port;
}

Expand Down Expand Up @@ -289,7 +370,7 @@ std::string ReadConfigFromArgument(std::string_view server_host,
}

PortFlag server_port;
if (!AbslParseFlag(_server_port, &server_port, &err)) {
if (!AbslParseFlag(_server_port, &server_port, &err) || server_port.port == 0u) {
err_msg << ",Invalid Server Port: " << _server_port;
}

Expand Down Expand Up @@ -374,6 +455,8 @@ std::string ReadConfigFromArgument(std::string_view server_host,
void SetClientUsageMessage(std::string_view exec_path) {
absl::SetProgramUsageMessage(absl::StrCat("Usage: ", Basename(exec_path), " [options ...]\n", R"(
-K, --config <file> Read config from a file
-t Don't run, just test the configuration file
-v, --version Print yass version
--server_host <host> Remote server on given host
--server_port <port> Remote server on given port
--local_host <host> Local proxy server on given host
Expand All @@ -396,6 +479,8 @@ void SetClientUsageMessage(std::string_view exec_path) {
void SetServerUsageMessage(std::string_view exec_path) {
absl::SetProgramUsageMessage(absl::StrCat("Usage: ", Basename(exec_path), " [options ...]\n", R"(
-K, --config <file> Read config from a file
-t Don't run, just test the configuration file
-v, --version Print yass version
--server_host <host> Server on given host
--server_port <port> Server on given port
--username <username> Server user
Expand Down
3 changes: 3 additions & 0 deletions src/config/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ enum ProgramType {
extern const ProgramType pType;
const char* ProgramTypeToStr(ProgramType type);

extern bool testOnlyMode;
void ReadConfigFileAndArguments(int argc, const char** argv);

std::string ValidateConfig();

std::string ReadConfigFromArgument(std::string_view server_host,
std::string_view server_sni,
std::string_view server_port,
Expand Down
6 changes: 6 additions & 0 deletions src/config/config_version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

namespace config {

bool testOnlyMode = false;

static void ParseConfigFileOption(int argc, const char** argv) {
int pos = 1;
while (pos < argc) {
Expand Down Expand Up @@ -63,6 +65,10 @@ static void ParseConfigFileOption(int argc, const char** argv) {
argv[pos + 1] = "";
pos += 2;
continue;
} else if (arg == "-t") {
testOnlyMode = true;
argv[pos] = "";
pos += 1;
} else if (arg == "-version" || arg == "--version") {
std::cout << absl::flags_internal::ShortProgramInvocationName() << " " << YASS_APP_TAG
<< " type: " << ProgramTypeToStr(pType) << std::endl;
Expand Down
9 changes: 9 additions & 0 deletions src/gtk/yass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ int main(int argc, const char** argv) {
config::SetClientUsageMessage(exec_path);
config::ReadConfigFileAndArguments(argc, argv);

std::string err = config::ValidateConfig();
if (!err.empty()) {
LOG(WARNING) << "Failed to validate config: " << err;
}
if (config::testOnlyMode) {
LOG(WARNING) << "Configuration Validated";
return 0;
}

#if !GLIB_CHECK_VERSION(2, 35, 0)
// GLib type system initialization. It's unclear if it's still required for
// any remaining code. Most likely this is superfluous as gtk_init() ought
Expand Down
9 changes: 9 additions & 0 deletions src/gtk4/yass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,15 @@ int main(int argc, const char** argv) {
config::SetClientUsageMessage(exec_path);
config::ReadConfigFileAndArguments(argc, argv);

std::string err = config::ValidateConfig();
if (!err.empty()) {
LOG(WARNING) << "Failed to validate config: " << err;
}
if (config::testOnlyMode) {
LOG(WARNING) << "Configuration Validated";
return 0;
}

#if !GLIB_CHECK_VERSION(2, 35, 0)
// GLib type system initialization. It's unclear if it's still required for
// any remaining code. Most likely this is superfluous as gtk_init() ought
Expand Down
9 changes: 9 additions & 0 deletions src/mac/main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,14 @@ int main(int argc, const char** argv) {
config::SetClientUsageMessage(exec_path);
config::ReadConfigFileAndArguments(argc, argv);

std::string err = config::ValidateConfig();
if (!err.empty()) {
LOG(WARNING) << "Failed to validate config: " << err;
}
if (config::testOnlyMode) {
LOG(WARNING) << "Configuration Validated";
return 0;
}

return NSApplicationMain(argc, argv);
}
9 changes: 9 additions & 0 deletions src/qt6/yass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ int main(int argc, const char** argv) {
config::SetClientUsageMessage(exec_path);
config::ReadConfigFileAndArguments(argc, argv);

std::string err = config::ValidateConfig();
if (!err.empty()) {
LOG(WARNING) << "Failed to validate config: " << err;
}
if (config::testOnlyMode) {
LOG(WARNING) << "Configuration Validated";
return 0;
}

YASSApp program(argc, const_cast<char**>(argv));

// call program init
Expand Down
10 changes: 10 additions & 0 deletions src/server/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ int main(int argc, const char* argv[]) {
config::SetServerUsageMessage(exec_path);
config::ReadConfigFileAndArguments(argc, argv);

std::string err = config::ValidateConfig();
if (!err.empty()) {
LOG(WARNING) << "Failed to validate config: " << err;
return -1;
}
if (config::testOnlyMode) {
LOG(WARNING) << "Configuration Validated";
return 0;
}

#ifdef _WIN32
int iResult = 0;
WSADATA wsaData = {0};
Expand Down
9 changes: 9 additions & 0 deletions src/win32/yass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
config::SetClientUsageMessage(exec_path);
config::ReadConfigFileAndArguments(argc, &argv[0]);

std::string err = config::ValidateConfig();
if (!err.empty()) {
LOG(WARNING) << "Failed to validate config: " << err;
}
if (config::testOnlyMode) {
LOG(WARNING) << "Configuration Validated";
return 0;
}

int iResult = 0;
WSADATA wsaData = {0};
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
Expand Down

0 comments on commit a8c4284

Please sign in to comment.