Skip to content

Commit

Permalink
feat: inbound authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
arm64v8a committed Jan 12, 2023
1 parent 10d7d94 commit 6a344bc
Show file tree
Hide file tree
Showing 22 changed files with 288 additions and 119 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,14 @@ set(PROJECT_SOURCES
main/NekoRay.cpp
main/NekoRay_Utils.cpp
main/QJS.cpp
main/HTTPRequestHelper.cpp

3rdparty/base64.cpp
3rdparty/qrcodegen.cpp
3rdparty/QtExtKeySequenceEdit.cpp

qv2ray/v2/ui/LogHighlighter.cpp
qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp
qv2ray/v2/utils/HTTPRequestHelper.cpp
qv2ray/v2/components/proxy/QvProxyConfigurator.cpp
qv2ray/v2/ui/widgets/common/QJsonModel.cpp
qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp
Expand Down Expand Up @@ -174,7 +174,7 @@ set(PROJECT_SOURCES
sys/AutoRun.cpp

ui/ThemeManager.cpp
ui/TrayIcon.cpp
ui/Icon.cpp

ui/mainwindow_grpc.cpp
ui/mainwindow.cpp
Expand Down
152 changes: 90 additions & 62 deletions db/ConfigBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,34 +100,28 @@ namespace NekoRay {
}
}

#define DOMAIN_USER_RULE \
for (const auto &line: SplitLines(dataStore->routing->proxy_domain)) { \
if (line.startsWith("#")) continue; \
if (dataStore->dns_routing) status->domainListDNSRemote += line; \
status->domainListRemote += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->direct_domain)) { \
if (line.startsWith("#")) continue; \
if (dataStore->dns_routing) status->domainListDNSDirect += line; \
status->domainListDirect += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->block_domain)) { \
if (line.startsWith("#")) continue; \
status->domainListBlock += line; \
#define DOMAIN_USER_RULE \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_domain)) { \
if (dataStore->dns_routing) status->domainListDNSRemote += line; \
status->domainListRemote += line; \
} \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_domain)) { \
if (dataStore->dns_routing) status->domainListDNSDirect += line; \
status->domainListDirect += line; \
} \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->block_domain)) { \
status->domainListBlock += line; \
}

#define IP_USER_RULE \
for (const auto &line: SplitLines(dataStore->routing->block_ip)) { \
if (line.startsWith("#")) continue; \
status->ipListBlock += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->proxy_ip)) { \
if (line.startsWith("#")) continue; \
status->ipListRemote += line; \
} \
for (const auto &line: SplitLines(dataStore->routing->direct_ip)) { \
if (line.startsWith("#")) continue; \
status->ipListDirect += line; \
#define IP_USER_RULE \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->block_ip)) { \
status->ipListBlock += line; \
} \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->proxy_ip)) { \
status->ipListRemote += line; \
} \
for (const auto &line: SplitLinesSkipSharp(dataStore->routing->direct_ip)) { \
status->ipListDirect += line; \
}

// V2Ray
Expand All @@ -147,32 +141,49 @@ namespace NekoRay {
};

// socks-in
if (InRange(dataStore->inbound_socks_port, 1, 65535) && !status->forTest) {
QJsonObject socksInbound;
socksInbound["tag"] = "socks-in";
socksInbound["protocol"] = "socks";
socksInbound["listen"] = dataStore->inbound_address;
socksInbound["port"] = dataStore->inbound_socks_port;
socksInbound["settings"] = QJsonObject{
{"auth", "noauth"},
{"udp", true},
};
if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "socks-in";
inboundObj["protocol"] = "socks";
inboundObj["listen"] = dataStore->inbound_address;
inboundObj["port"] = dataStore->inbound_socks_port;
QJsonObject socksSettings = {{"udp", true}};
if (dataStore->fake_dns || dataStore->sniffing_mode != SniffingMode::DISABLE) {
socksInbound["sniffing"] = sniffing;
inboundObj["sniffing"] = sniffing;
}
if (dataStore->inbound_auth->NeedAuth()) {
socksSettings["auth"] = "password";
socksSettings["accounts"] = QJsonArray{
QJsonObject{
{"user", dataStore->inbound_auth->username},
{"pass", dataStore->inbound_auth->password},
},
};
}
status->inbounds += socksInbound;
inboundObj["settings"] = socksSettings;
status->inbounds += inboundObj;
}
// http-in
if (InRange(dataStore->inbound_http_port, 1, 65535) && !status->forTest) {
QJsonObject socksInbound;
socksInbound["tag"] = "http-in";
socksInbound["protocol"] = "http";
socksInbound["listen"] = dataStore->inbound_address;
socksInbound["port"] = dataStore->inbound_http_port;
if (IsValidPort(dataStore->inbound_http_port) && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "http-in";
inboundObj["protocol"] = "http";
inboundObj["listen"] = dataStore->inbound_address;
inboundObj["port"] = dataStore->inbound_http_port;
if (dataStore->sniffing_mode != SniffingMode::DISABLE) {
socksInbound["sniffing"] = sniffing;
inboundObj["sniffing"] = sniffing;
}
status->inbounds += socksInbound;
if (dataStore->inbound_auth->NeedAuth()) {
inboundObj["settings"] = QJsonObject{
{"accounts", QJsonArray{
QJsonObject{
{"user", dataStore->inbound_auth->username},
{"pass", dataStore->inbound_auth->password},
},
}},
};
}
status->inbounds += inboundObj;
}

// Outbounds
Expand Down Expand Up @@ -431,12 +442,12 @@ namespace NekoRay {
if (thisExternalStat > 0) {
if (ent->type == "custom") {
auto bean = ent->CustomBean();
if (InRange(bean->mapping_port, 1, 65535)) {
if (IsValidPort(bean->mapping_port)) {
ext_mapping_port = bean->mapping_port;
} else {
ext_mapping_port = MkPort();
}
if (InRange(bean->socks_port, 1, 65535)) {
if (IsValidPort(bean->socks_port)) {
ext_socks_port = bean->socks_port;
} else {
ext_socks_port = MkPort();
Expand Down Expand Up @@ -617,17 +628,25 @@ namespace NekoRay {
// Inbounds

// mixed-in
if (InRange(dataStore->inbound_socks_port, 1, 65535) && !status->forTest) {
QJsonObject socksInbound;
socksInbound["tag"] = "mixed-in";
socksInbound["type"] = "mixed";
socksInbound["listen"] = dataStore->inbound_address;
socksInbound["listen_port"] = dataStore->inbound_socks_port;
if (IsValidPort(dataStore->inbound_socks_port) && !status->forTest) {
QJsonObject inboundObj;
inboundObj["tag"] = "mixed-in";
inboundObj["type"] = "mixed";
inboundObj["listen"] = dataStore->inbound_address;
inboundObj["listen_port"] = dataStore->inbound_socks_port;
if (dataStore->sniffing_mode != SniffingMode::DISABLE) {
socksInbound["sniff"] = true;
socksInbound["sniff_override_destination"] = dataStore->sniffing_mode == SniffingMode::FOR_DESTINATION;
inboundObj["sniff"] = true;
inboundObj["sniff_override_destination"] = dataStore->sniffing_mode == SniffingMode::FOR_DESTINATION;
}
if (dataStore->inbound_auth->NeedAuth()) {
inboundObj["users"] = QJsonArray{
QJsonObject{
{"username", dataStore->inbound_auth->username},
{"password", dataStore->inbound_auth->password},
},
};
}
status->inbounds += socksInbound;
status->inbounds += inboundObj;
}

// Outbounds
Expand Down Expand Up @@ -839,26 +858,32 @@ namespace NekoRay {
}

QString WriteVPNSingBoxConfig() {
//
// user rule
QString process_name_rule = dataStore->vpn_bypass_process.trimmed();
if (!process_name_rule.isEmpty()) {
auto arr = SplitLines(process_name_rule);
auto arr = SplitLinesSkipSharp(process_name_rule);
QJsonObject rule{{"outbound", "direct"},
{"process_name", QList2QJsonArray(arr)}};
process_name_rule = "," + QJsonObject2QString(rule, false);
}
QString cidr_rule = dataStore->vpn_bypass_cidr.trimmed();
if (!cidr_rule.isEmpty()) {
auto arr = SplitLines(cidr_rule);
auto arr = SplitLinesSkipSharp(cidr_rule);
QJsonObject rule{{"outbound", "direct"},
{"ip_cidr", QList2QJsonArray(arr)}};
cidr_rule = "," + QJsonObject2QString(rule, false);
}
//
// tun name
auto tun_name = "nekoray-tun";
#ifdef Q_OS_MACOS
tun_name = "utun9";
#endif
// auth
QString socks_user_pass;
if (dataStore->inbound_auth->NeedAuth()) {
socks_user_pass = R"( "username": "%1", "password": "%2", )";
socks_user_pass = socks_user_pass.arg(dataStore->inbound_auth->username, dataStore->inbound_auth->password);
}
// gen config
auto configFn = ":/neko/vpn/sing-box-vpn.json";
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json";
Expand All @@ -870,6 +895,7 @@ namespace NekoRay {
.replace("%CIDR_RULE%", cidr_rule)
.replace("%TUN_NAME%", tun_name)
.replace("%STRICT_ROUTE%", dataStore->vpn_strict_route ? "true" : "false")
.replace("%SOCKS_USER_PASS%", socks_user_pass)
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
// hook.js
auto source = qjs::ReadHookJS();
Expand All @@ -891,11 +917,13 @@ namespace NekoRay {
}

QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath) {
#ifdef Q_OS_WIN
return {};
#endif
// gen script
auto scriptFn = ":/neko/vpn/vpn-run-root.sh";
if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh";
auto script = ReadFileText(scriptFn)
.replace("$PORT", Int2String(dataStore->inbound_socks_port))
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
.replace("$PROTECT_LISTEN_PATH", protectPath)
.replace("$CONFIG_PATH", configPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@

#include "main/NekoRay.hpp"

#include "qv2ray/wrapper.hpp"

namespace Qv2ray::common::network {
namespace NekoRay::network {

NekoHTTPResponse NetworkRequestHelper::HttpGet(const QUrl &url) {
QNetworkRequest request;
Expand All @@ -22,13 +20,16 @@ namespace Qv2ray::common::network {
p.setType(IS_NEKO_BOX ? QNetworkProxy::HttpProxy : QNetworkProxy::Socks5Proxy);
p.setHostName("127.0.0.1");
p.setPort(NekoRay::dataStore->inbound_socks_port);
if (dataStore->inbound_auth->NeedAuth()) {
p.setUser(dataStore->inbound_auth->username);
p.setPassword(dataStore->inbound_auth->password);
}
accessManager.setProxy(p);
if (NekoRay::dataStore->started_id < 0) {
return NekoHTTPResponse{QObject::tr("Request with proxy but no profile started.")};
}
}
if (accessManager.proxy().type() == QNetworkProxy::Socks5Proxy) {
DEBUG("Adding HostNameLookupCapability to proxy.");
auto cap = accessManager.proxy().capabilities();
accessManager.proxy().setCapabilities(cap | QNetworkProxy::HostNameLookupCapability);
}
Expand Down Expand Up @@ -69,4 +70,4 @@ namespace Qv2ray::common::network {
return "";
}

} // namespace Qv2ray::common::network
} // namespace NekoRay::network
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <QObject>
#include <functional>

namespace Qv2ray::common::network {
namespace NekoRay::network {
struct NekoHTTPResponse {
QString error;
QByteArray data;
Expand All @@ -26,6 +26,6 @@ namespace Qv2ray::common::network {

static QString GetHeader(const QList<QPair<QByteArray, QByteArray>> &header, const QString &name);
};
} // namespace Qv2ray::common::network
} // namespace NekoRay::network

using namespace Qv2ray::common::network;
using namespace NekoRay::network;
22 changes: 16 additions & 6 deletions main/NekoRay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace NekoRay {

DataStore::DataStore() : JsonStore() {
_add(new configItem("extraCore", dynamic_cast<JsonStore *>(extraCore), itemType::jsonStore));
_add(new configItem("inbound_auth", dynamic_cast<JsonStore *>(inbound_auth), itemType::jsonStore));

_add(new configItem("user_agent", &user_agent, itemType::string));
_add(new configItem("test_url", &test_url, itemType::string));
Expand Down Expand Up @@ -112,12 +113,12 @@ namespace NekoRay {

QString Routing::DisplayRouting() const {
return QString("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6")
.arg(SplitLines(proxy_domain).join(","))
.arg(SplitLines(proxy_ip).join(","))
.arg(SplitLines(direct_domain).join(","))
.arg(SplitLines(direct_ip).join(","))
.arg(SplitLines(block_domain).join(","))
.arg(SplitLines(block_ip).join(","));
.arg(SplitLinesSkipSharp(proxy_domain).join(","))
.arg(SplitLinesSkipSharp(proxy_ip).join(","))
.arg(SplitLinesSkipSharp(direct_domain).join(","))
.arg(SplitLinesSkipSharp(direct_ip).join(","))
.arg(SplitLinesSkipSharp(block_domain).join(","))
.arg(SplitLinesSkipSharp(block_ip).join(","));
}

QStringList Routing::List() {
Expand Down Expand Up @@ -163,6 +164,15 @@ namespace NekoRay {
core_map = QJsonObject2QString(obj, true);
}

InboundAuthorization::InboundAuthorization() : JsonStore() {
_add(new configItem("user", &this->username, itemType::string));
_add(new configItem("pass", &this->password, itemType::string));
}

bool InboundAuthorization::NeedAuth() const {
return !username.trimmed().isEmpty() && !password.trimmed().isEmpty();
}

// 添加关联
void JsonStore::_add(configItem *item) {
_map.insert(item->name, QSharedPointer<configItem>(item));
Expand Down
11 changes: 11 additions & 0 deletions main/NekoRay_DataStore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ namespace NekoRay {
void Delete(const QString &id);
};

class InboundAuthorization : public JsonStore {
public:
QString username;
QString password;

InboundAuthorization();

[[nodiscard]] bool NeedAuth() const;
};

class DataStore : public JsonStore {
public:
// Running
Expand Down Expand Up @@ -98,6 +108,7 @@ namespace NekoRay {
QString inbound_address = "127.0.0.1";
int inbound_socks_port = 2080; // or Mixed
int inbound_http_port = -2081;
InboundAuthorization *inbound_auth = new InboundAuthorization;
QString custom_inbound = "{\"inbounds\": []}";

// DNS
Expand Down
Loading

0 comments on commit 6a344bc

Please sign in to comment.