mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 02:40:20 +08:00
refactor: refactored Route Generator - 3, WARN: NOT TESTED
This commit is contained in:
parent
8d94f6ca5f
commit
d8b0b37c6f
@ -1 +1 @@
|
||||
5851
|
||||
5852
|
||||
|
@ -7,8 +7,13 @@ namespace Qv2ray::core::connection::generation
|
||||
{
|
||||
namespace routing
|
||||
{
|
||||
ROUTERULE GenerateSingleRouteRule(const QString &str, bool isDomain, const QString &outboundTag, const QString &type = "field");
|
||||
ROUTERULE GenerateSingleRouteRule(const QStringList &list, bool isDomain, const QString &outboundTag, const QString &type = "field");
|
||||
enum RuleType
|
||||
{
|
||||
RULE_DOMAINS,
|
||||
RULE_IPS
|
||||
};
|
||||
ROUTERULE GenerateSingleRouteRule(RuleType t, const QString &str, const QString &outboundTag, const QString &type = "field");
|
||||
ROUTERULE GenerateSingleRouteRule(RuleType t, const QStringList &list, const QString &outboundTag, const QString &type = "field");
|
||||
QJsonObject GenerateDNS(bool withLocalhost, const QvConfig_DNS &dnsServer);
|
||||
} // namespace routing
|
||||
|
||||
|
@ -18,17 +18,22 @@ namespace Qv2ray::core::connection::generation::routing
|
||||
return root;
|
||||
}
|
||||
|
||||
ROUTERULE GenerateSingleRouteRule(const QString &str, bool isDomain, const QString &outboundTag, const QString &type)
|
||||
ROUTERULE GenerateSingleRouteRule(RuleType t, const QString &str, const QString &outboundTag, const QString &type)
|
||||
{
|
||||
return GenerateSingleRouteRule(QStringList{ str }, isDomain, outboundTag, type);
|
||||
return GenerateSingleRouteRule(t, QStringList{ str }, outboundTag, type);
|
||||
}
|
||||
|
||||
ROUTERULE GenerateSingleRouteRule(const QStringList &rules, bool isDomain, const QString &outboundTag, const QString &type)
|
||||
ROUTERULE GenerateSingleRouteRule(RuleType t, const QStringList &rules, const QString &outboundTag, const QString &type)
|
||||
{
|
||||
ROUTERULE root;
|
||||
auto list = rules;
|
||||
list.removeAll("");
|
||||
root.insert(isDomain ? "domain" : "ip", QJsonArray::fromStringList(rules));
|
||||
switch (t)
|
||||
{
|
||||
case RULE_IPS: root.insert("domain", QJsonArray::fromStringList(rules)); break;
|
||||
case RULE_DOMAINS: root.insert("ip", QJsonArray::fromStringList(rules)); break;
|
||||
default: Q_UNREACHABLE();
|
||||
}
|
||||
JADD(outboundTag, type)
|
||||
return root;
|
||||
}
|
||||
|
@ -53,14 +53,14 @@ namespace Qv2ray::core::handler
|
||||
QJsonArray rulesList;
|
||||
|
||||
// Private IPs should always NOT TO PROXY!
|
||||
rulesList.append(GenerateSingleRouteRule("geoip:private", false, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, "geoip:private", OUTBOUND_TAG_DIRECT));
|
||||
//
|
||||
if (!enableProxy)
|
||||
{
|
||||
// This is added to disable all proxies, as a alternative influence of #64
|
||||
rulesList.append(GenerateSingleRouteRule("regexp:.*", true, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule("0.0.0.0/0", false, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule("::/0", false, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_DOMAINS, "regexp:.*", OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, "0.0.0.0/0", OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, "::/0", OUTBOUND_TAG_DIRECT));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -68,45 +68,122 @@ namespace Qv2ray::core::handler
|
||||
// Blocked.
|
||||
if (!routeConfig.ips.block.isEmpty())
|
||||
{
|
||||
rulesList.append(GenerateSingleRouteRule(routeConfig.ips.block, false, OUTBOUND_TAG_BLACKHOLE));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, routeConfig.ips.block, OUTBOUND_TAG_BLACKHOLE));
|
||||
}
|
||||
if (!routeConfig.domains.block.isEmpty())
|
||||
{
|
||||
rulesList.append(GenerateSingleRouteRule(routeConfig.domains.block, true, OUTBOUND_TAG_BLACKHOLE));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_DOMAINS, routeConfig.domains.block, OUTBOUND_TAG_BLACKHOLE));
|
||||
}
|
||||
//
|
||||
// Proxied
|
||||
if (!routeConfig.ips.proxy.isEmpty())
|
||||
{
|
||||
rulesList.append(GenerateSingleRouteRule(routeConfig.ips.proxy, false, outTag));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, routeConfig.ips.proxy, outTag));
|
||||
}
|
||||
if (!routeConfig.domains.proxy.isEmpty())
|
||||
{
|
||||
rulesList.append(GenerateSingleRouteRule(routeConfig.domains.proxy, true, outTag));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_DOMAINS, routeConfig.domains.proxy, outTag));
|
||||
}
|
||||
//
|
||||
// Directed
|
||||
if (!routeConfig.ips.direct.isEmpty())
|
||||
{
|
||||
rulesList.append(GenerateSingleRouteRule(routeConfig.ips.direct, false, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, routeConfig.ips.direct, OUTBOUND_TAG_DIRECT));
|
||||
}
|
||||
if (!routeConfig.domains.direct.isEmpty())
|
||||
{
|
||||
rulesList.append(GenerateSingleRouteRule(routeConfig.domains.direct, true, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_DOMAINS, routeConfig.domains.direct, OUTBOUND_TAG_DIRECT));
|
||||
}
|
||||
//
|
||||
// Check if CN needs proxy, or direct.
|
||||
if (bypassCN)
|
||||
{
|
||||
// No proxy agains CN addresses.
|
||||
rulesList.append(GenerateSingleRouteRule("geoip:cn", false, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule("geosite:cn", true, OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, "geoip:cn", OUTBOUND_TAG_DIRECT));
|
||||
rulesList.append(GenerateSingleRouteRule(RULE_IPS, "geosite:cn", OUTBOUND_TAG_DIRECT));
|
||||
}
|
||||
}
|
||||
|
||||
root.insert("rules", rulesList);
|
||||
return root;
|
||||
}
|
||||
INBOUNDS RouteHandler::GenerateDefaultInbounds() const
|
||||
{
|
||||
|
||||
#define INCONF GlobalConfig.inboundConfig
|
||||
INBOUNDS inboundsList;
|
||||
const static QJsonObject sniffingOff{ { "enabled", false } };
|
||||
const static QJsonObject sniffingOn{ { "enabled", true }, { "destOverride", QJsonArray{ "http", "tls" } } };
|
||||
|
||||
// HTTP Inbound
|
||||
if (GlobalConfig.inboundConfig.useHTTP)
|
||||
{
|
||||
const auto httpInSettings = GenerateHTTPIN(INCONF.httpSettings.useAuth, { INCONF.httpSettings.account });
|
||||
const auto httpInboundObject = GenerateInboundEntry(INCONF.listenip, //
|
||||
INCONF.httpSettings.port, //
|
||||
"http", //
|
||||
httpInSettings, //
|
||||
"http_IN", //
|
||||
{ INCONF.httpSettings.sniffing ? sniffingOn : sniffingOff });
|
||||
inboundsList.append(httpInboundObject);
|
||||
}
|
||||
|
||||
// SOCKS Inbound
|
||||
if (INCONF.useSocks)
|
||||
{
|
||||
const auto socksInSettings = GenerateSocksIN(INCONF.socksSettings.useAuth ? "password" : "noauth", //
|
||||
{ INCONF.socksSettings.account }, //
|
||||
INCONF.socksSettings.enableUDP, //
|
||||
INCONF.socksSettings.localIP);
|
||||
const auto socksInboundObject = GenerateInboundEntry(INCONF.listenip, //
|
||||
INCONF.socksSettings.port, //
|
||||
"socks", //
|
||||
socksInSettings, //
|
||||
"socks_IN", //
|
||||
{ INCONF.socksSettings.sniffing ? sniffingOn : sniffingOff });
|
||||
inboundsList.append(socksInboundObject);
|
||||
}
|
||||
|
||||
// TPROXY
|
||||
if (INCONF.useTPROXY)
|
||||
{
|
||||
QList<QString> networks;
|
||||
if (INCONF.tProxySettings.hasTCP)
|
||||
networks << "tcp";
|
||||
if (INCONF.tProxySettings.hasUDP)
|
||||
networks << "udp";
|
||||
const auto tproxy_network = networks.join(",");
|
||||
const auto tProxySettings = GenerateDokodemoIN("", 0, tproxy_network, 0, true, 0);
|
||||
const static QJsonObject sniffingSettings = { { "enabled", true }, { "destOverride", QJsonArray{ "http", "tls" } } };
|
||||
// tProxy IPv4 Settings
|
||||
{
|
||||
LOG(MODULE_CONNECTION, "Processing tProxy IPv4 inbound")
|
||||
auto tProxyIn = GenerateInboundEntry(INCONF.tProxySettings.tProxyIP, //
|
||||
INCONF.tProxySettings.port, //
|
||||
"dokodemo-door", //
|
||||
tProxySettings, //
|
||||
"tproxy_IN", //
|
||||
sniffingSettings);
|
||||
tProxyIn.insert("streamSettings", QJsonObject{ { "sockopt", QJsonObject{ { "tproxy", INCONF.tProxySettings.mode } } } });
|
||||
inboundsList.append(tProxyIn);
|
||||
}
|
||||
if (!INCONF.tProxySettings.tProxyV6IP.isEmpty())
|
||||
{
|
||||
LOG(MODULE_CONNECTION, "Processing tProxy IPv6 inbound")
|
||||
auto tProxyIn = GenerateInboundEntry(INCONF.tProxySettings.tProxyV6IP, //
|
||||
INCONF.tProxySettings.port, //
|
||||
"dokodemo-door", //
|
||||
tProxySettings, //
|
||||
"tproxy_IN_V6", //
|
||||
sniffingSettings);
|
||||
tProxyIn.insert("streamSettings", QJsonObject{ { "sockopt", QJsonObject{ { "tproxy", INCONF.tProxySettings.mode } } } });
|
||||
inboundsList.append(tProxyIn);
|
||||
}
|
||||
}
|
||||
|
||||
#undef INCONF
|
||||
return inboundsList;
|
||||
}
|
||||
// -------------------------- END CONFIG GENERATIONS
|
||||
//
|
||||
// BEGIN RUNTIME CONFIG GENERATION
|
||||
@ -192,8 +269,7 @@ namespace Qv2ray::core::handler
|
||||
}
|
||||
root["routing"] = GenerateRoutes(connConf.enableProxy, connConf.bypassCN, tag, routeConf);
|
||||
//
|
||||
// Process forward proxy
|
||||
//
|
||||
// Forward proxy
|
||||
if (fpConf.enableForwardProxy)
|
||||
{
|
||||
auto outboundArray = root["outbounds"].toArray();
|
||||
@ -201,25 +277,31 @@ namespace Qv2ray::core::handler
|
||||
if (firstOutbound[QV2RAY_USE_FPROXY_KEY].toBool(false))
|
||||
{
|
||||
LOG(MODULE_CONNECTION, "Applying forward proxy to current connection.")
|
||||
QJsonObject proxy;
|
||||
proxy["tag"] = OUTBOUND_TAG_FORWARD_PROXY;
|
||||
firstOutbound["proxySettings"] = proxy;
|
||||
firstOutbound["proxySettings"] = QJsonObject{ { "tag", OUTBOUND_TAG_FORWARD_PROXY } };
|
||||
|
||||
// FP Outbound.
|
||||
if (fpConf.type.toLower() == "http" || fpConf.type.toLower() == "socks")
|
||||
// Forward proxy.
|
||||
if (fpConf.type.isEmpty())
|
||||
{
|
||||
auto fpOutbound =
|
||||
GenerateHTTPSOCKSOut(fpConf.serverAddress, fpConf.port, fpConf.useAuth, fpConf.username, fpConf.password);
|
||||
outboundArray.push_back(
|
||||
GenerateOutboundEntry(fpConf.type.toLower(), fpOutbound, {}, {}, "0.0.0.0", OUTBOUND_TAG_FORWARD_PROXY));
|
||||
DEBUG(MODULE_CONNECTION, "WARNING: Empty forward proxy type.")
|
||||
}
|
||||
else if (!fpConf.type.isEmpty())
|
||||
else if (fpConf.type.toLower() != "http" && fpConf.type.toLower() != "socks")
|
||||
{
|
||||
DEBUG(MODULE_CONNECTION, "WARNING: Unsupported forward proxy type: " + fpConf.type)
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(MODULE_CONNECTION, "WARNING: Empty forward proxy type.")
|
||||
const auto forwardProxySettings = GenerateHTTPSOCKSOut(fpConf.serverAddress, //
|
||||
fpConf.port, //
|
||||
fpConf.useAuth, //
|
||||
fpConf.username, //
|
||||
fpConf.password);
|
||||
const auto forwardProxyOutbound = GenerateOutboundEntry(fpConf.type.toLower(), //
|
||||
forwardProxySettings, //
|
||||
{}, //
|
||||
{}, //
|
||||
"0.0.0.0", //
|
||||
OUTBOUND_TAG_FORWARD_PROXY);
|
||||
outboundArray.push_back(forwardProxyOutbound);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -231,7 +313,6 @@ namespace Qv2ray::core::handler
|
||||
outboundArray.replace(0, firstOutbound);
|
||||
root["outbounds"] = outboundArray;
|
||||
}
|
||||
#undef fpConf
|
||||
//
|
||||
// Process FREEDOM and BLACKHOLE outbound
|
||||
{
|
||||
@ -272,107 +353,28 @@ namespace Qv2ray::core::handler
|
||||
// logObject.insert("error", QV2RAY_CONFIG_PATH + QV2RAY_VCORE_LOG_DIRNAME + QV2RAY_VCORE_ERROR_LOG_FILENAME);
|
||||
QJsonIO::SetValue(root, V2RayLogLevel[GlobalConfig.logLevel], "log", "loglevel");
|
||||
|
||||
{
|
||||
//
|
||||
// Process DNS
|
||||
const auto hasDNS = root.contains("dns") && !root.value("dns").toObject().isEmpty();
|
||||
if (hasDNS)
|
||||
{
|
||||
// We assume the users are using THEIR DNS settings.
|
||||
LOG(MODULE_CONNECTION, "Found DNS settings specified manually, skipping inserting GlobalConfig")
|
||||
}
|
||||
else
|
||||
{
|
||||
root.insert("dns", GenerateDNS(connConf.withLocalDNS, dnsConf));
|
||||
}
|
||||
}
|
||||
//
|
||||
// Process DNS
|
||||
const auto hasDNS = root.contains("dns") && !root.value("dns").toObject().isEmpty();
|
||||
if (!hasDNS)
|
||||
{
|
||||
//
|
||||
// If inbounds list is empty we append our global configured inbounds to the config.
|
||||
// The setting applies to BOTH complex config AND simple config.
|
||||
// Just to ensure there's AT LEAST 1 possible inbound is being configured.
|
||||
if (!root.contains("inbounds") || root.value("inbounds").toArray().empty())
|
||||
{
|
||||
#define INCONF GlobalConfig.inboundConfig
|
||||
INBOUNDS inboundsList;
|
||||
const static QJsonObject sniffingOff{ { "enabled", false } };
|
||||
const static QJsonObject sniffingOn{ { "enabled", true }, { "destOverride", QJsonArray{ "http", "tls" } } };
|
||||
|
||||
// HTTP Inbound
|
||||
if (GlobalConfig.inboundConfig.useHTTP)
|
||||
{
|
||||
const auto httpInSettings = GenerateHTTPIN(INCONF.httpSettings.useAuth, { INCONF.httpSettings.account });
|
||||
const auto httpInboundObject = GenerateInboundEntry(INCONF.listenip, //
|
||||
INCONF.httpSettings.port, //
|
||||
"http", //
|
||||
httpInSettings, //
|
||||
"http_IN", //
|
||||
{ INCONF.httpSettings.sniffing ? sniffingOn : sniffingOff });
|
||||
inboundsList.append(httpInboundObject);
|
||||
}
|
||||
|
||||
// SOCKS Inbound
|
||||
if (INCONF.useSocks)
|
||||
{
|
||||
const auto socksInSettings = GenerateSocksIN(INCONF.socksSettings.useAuth ? "password" : "noauth", //
|
||||
{ INCONF.socksSettings.account }, //
|
||||
INCONF.socksSettings.enableUDP, //
|
||||
INCONF.socksSettings.localIP);
|
||||
const auto socksInboundObject = GenerateInboundEntry(INCONF.listenip, //
|
||||
INCONF.socksSettings.port, //
|
||||
"socks", //
|
||||
socksInSettings, //
|
||||
"socks_IN", //
|
||||
{ INCONF.socksSettings.sniffing ? sniffingOn : sniffingOff });
|
||||
inboundsList.append(socksInboundObject);
|
||||
}
|
||||
|
||||
// TPROXY
|
||||
if (INCONF.useTPROXY)
|
||||
{
|
||||
QList<QString> networks;
|
||||
if (INCONF.tProxySettings.hasTCP)
|
||||
networks << "tcp";
|
||||
if (INCONF.tProxySettings.hasUDP)
|
||||
networks << "udp";
|
||||
const auto tproxy_network = networks.join(",");
|
||||
const auto tProxySettings = GenerateDokodemoIN("", 0, tproxy_network, 0, true, 0);
|
||||
const static QJsonObject sniffingSettings = { { "enabled", true }, { "destOverride", QJsonArray{ "http", "tls" } } };
|
||||
// tProxy IPv4 Settings
|
||||
{
|
||||
LOG(MODULE_CONNECTION, "Processing tProxy IPv4 inbound")
|
||||
auto tProxyIn = GenerateInboundEntry(INCONF.tProxySettings.tProxyIP, //
|
||||
INCONF.tProxySettings.port, //
|
||||
"dokodemo-door", //
|
||||
tProxySettings, //
|
||||
"tproxy_IN", //
|
||||
sniffingSettings);
|
||||
tProxyIn.insert("streamSettings", QJsonObject{ { "sockopt", QJsonObject{ { "tproxy", INCONF.tProxySettings.mode } } } });
|
||||
inboundsList.append(tProxyIn);
|
||||
}
|
||||
if (!INCONF.tProxySettings.tProxyV6IP.isEmpty())
|
||||
{
|
||||
LOG(MODULE_CONNECTION, "Processing tProxy IPv6 inbound")
|
||||
auto tProxyIn = GenerateInboundEntry(INCONF.tProxySettings.tProxyV6IP, //
|
||||
INCONF.tProxySettings.port, //
|
||||
"dokodemo-door", //
|
||||
tProxySettings, //
|
||||
"tproxy_IN_V6", //
|
||||
sniffingSettings);
|
||||
tProxyIn.insert("streamSettings", QJsonObject{ { "sockopt", QJsonObject{ { "tproxy", INCONF.tProxySettings.mode } } } });
|
||||
inboundsList.append(tProxyIn);
|
||||
}
|
||||
}
|
||||
|
||||
root["inbounds"] = inboundsList;
|
||||
DEBUG(MODULE_CONNECTION, "Added global config inbounds to the config")
|
||||
#undef INCONF
|
||||
}
|
||||
// API 0 speed issue when no tag is configured.
|
||||
// Process every inbounds to make sure a tag is configured, fixed
|
||||
FillupTagsFilter(root, "inbounds");
|
||||
root.insert("dns", GenerateDNS(connConf.withLocalDNS, dnsConf));
|
||||
LOG(MODULE_CONNECTION, "Added global DNS config")
|
||||
}
|
||||
|
||||
//
|
||||
// If inbounds list is empty, we append our global configured inbounds to the config.
|
||||
// The setting applies to BOTH complex config AND simple config.
|
||||
// Just to ensure there's AT LEAST 1 possible inbound is being configured.
|
||||
if (!root.contains("inbounds") || root.value("inbounds").toArray().empty())
|
||||
{
|
||||
root["inbounds"] = GenerateDefaultInbounds();
|
||||
DEBUG(MODULE_CONNECTION, "Added global inbound config")
|
||||
}
|
||||
// API 0 speed issue when no tag is configured.
|
||||
// Process every inbounds to make sure a tag is configured, fixed
|
||||
FillupTagsFilter(root, "inbounds");
|
||||
|
||||
//
|
||||
// Let's process some api features.
|
||||
if (hasAPI && GlobalConfig.kernelConfig.enableAPI)
|
||||
|
@ -29,6 +29,8 @@ namespace Qv2ray::core::handler
|
||||
CONFIGROOT GenerateFinalConfig(const ConnectionGroupPair &pair, bool hasAPI = true) const;
|
||||
CONFIGROOT GenerateFinalConfig(CONFIGROOT root, const GroupRoutingId &routingId, bool hasAPI = true) const;
|
||||
//
|
||||
INBOUNDS GenerateDefaultInbounds() const;
|
||||
//
|
||||
// Route Table Generation
|
||||
ROUTING GenerateRoutes(bool enableProxy, bool bypassCN, const QString &outboundTag, const QvConfig_Route &routeConfig) const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user