Merge pull request #88 from feisan/master

feat: add shadow-tls filtering and AnyTLS Surge INI import
This commit is contained in:
asdlokj1qpi23 authored and GitHub committed 2026-06-08 14:34:02 +08:00
commit 2eb4c199be
4 files changed
+140 -14

No files matched your search

+57
View File
@@ -0,0 +1,57 @@
FROM alpine:3.16 AS builder
LABEL maintainer="feisan"
ARG THREADS="4"
WORKDIR /
RUN set -xe && \
apk add --no-cache --virtual .build-tools git g++ build-base linux-headers cmake python3 && \
apk add --no-cache --virtual .build-deps curl-dev rapidjson-dev pcre2-dev yaml-cpp-dev && \
git clone --no-checkout https://github.com/ftk/quickjspp.git && \
cd quickjspp && \
git fetch origin 0c00c48895919fc02da3f191a2da06addeb07f09 && \
git checkout 0c00c48895919fc02da3f191a2da06addeb07f09 && \
git submodule update --init && \
cmake -DCMAKE_BUILD_TYPE=Release . && \
make quickjs -j $THREADS && \
install -d /usr/lib/quickjs/ && \
install -m644 quickjs/libquickjs.a /usr/lib/quickjs/ && \
install -d /usr/include/quickjs/ && \
install -m644 quickjs/quickjs.h quickjs/quickjs-libc.h /usr/include/quickjs/ && \
install -m644 quickjspp.hpp /usr/include && \
cd .. && \
git clone https://github.com/PerMalmberg/libcron --depth=1 && \
cd libcron && \
git submodule update --init && \
cmake -DCMAKE_BUILD_TYPE=Release . && \
make libcron -j $THREADS && \
install -m644 libcron/out/Release/liblibcron.a /usr/lib/ && \
install -d /usr/include/libcron/ && \
install -m644 libcron/include/libcron/* /usr/include/libcron/ && \
install -d /usr/include/date/ && \
install -m644 libcron/externals/date/include/date/* /usr/include/date/ && \
cd .. && \
git clone https://github.com/ToruNiina/toml11 --branch="v4.3.0" --depth=1 && \
cd toml11 && \
cmake -DCMAKE_CXX_STANDARD=11 . && \
make install -j $THREADS && \
cd ..
# Copy local source instead of cloning from GitHub
COPY . /subconverter
WORKDIR /subconverter
RUN python3 -m ensurepip && \
python3 -m pip install gitpython && \
python3 scripts/update_rules.py -c scripts/rules_config.conf && \
cmake -DCMAKE_BUILD_TYPE=Release . && \
make -j $THREADS
# build final image
FROM alpine:3.16
RUN apk add --no-cache --virtual subconverter-deps pcre2 libcurl yaml-cpp
COPY --from=builder /subconverter/subconverter /usr/bin/
COPY --from=builder /subconverter/base /base/
ENV TZ=Africa/Abidjan
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /base
CMD subconverter
EXPOSE 25500/tcp
+65 -14
View File
@@ -1031,7 +1031,7 @@ void explodeQuan(const std::string &quan, Proxy &node) {
//read link
for (uint32_t i = 6; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() < 2)
continue;
itemName = trim(vArray[0]);
@@ -2054,7 +2054,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
password = trim(configs[4]);
for (i = 6; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() < 2)
continue;
itemName = trim(vArray[0]);
@@ -2073,10 +2073,17 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
case "tfo"_hash:
tfo = itemVal;
break;
case "shadow-tls-sni"_hash:
case "shadow-tls-password"_hash:
case "shadow-tls-version"_hash:
port = "0";
break;
default:
continue;
}
}
if (port == "0")
continue;
if (!plugin.empty()) {
pluginopts = "obfs=" + pluginopts_mode;
pluginopts += pluginopts_host.empty() ? "" : ";obfs-host=" + pluginopts_host;
@@ -2095,7 +2102,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
continue;
for (i = 3; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() < 2)
continue;
itemName = trim(vArray[0]);
@@ -2120,10 +2127,17 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
case "tfo"_hash:
tfo = itemVal;
break;
case "shadow-tls-sni"_hash:
case "shadow-tls-password"_hash:
case "shadow-tls-version"_hash:
port = "0";
break;
default:
continue;
}
}
if (port == "0")
continue;
if (!plugin.empty()) {
pluginopts = "obfs=" + pluginopts_mode;
pluginopts += pluginopts_host.empty() ? "" : ";obfs-host=" + pluginopts_host;
@@ -2142,7 +2156,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
password = trim(configs[4]);
}
for (i = 5; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() < 2)
continue;
itemName = trim(vArray[0]);
@@ -2172,7 +2186,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
method = "auto";
for (i = 3; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2233,7 +2247,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
if (port == "0")
continue;
for (i = 3; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() < 2)
continue;
itemName = trim(vArray[0]);
@@ -2261,7 +2275,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
continue;
for (i = 3; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2304,7 +2318,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
continue;
for (i = 3; i < configs.size(); i++) {
vArray = split(configs[i], "=");
vArray = split_first(configs[i], "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2341,7 +2355,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
break;
case "wireguard"_hash:
for (i = 1; i < configs.size(); i++) {
vArray = split(trim(configs[i]), "=");
vArray = split_first(trim(configs[i]), "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2395,6 +2409,43 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
mtu, keepalive, test_url, "", udp, "");
parsePeers(node, peer);
break;
case "anytls"_hash: //Surge style anytls proxy
server = trim(configs[1]);
port = trim(configs[2]);
if (port == "0")
continue;
for (i = 3; i < configs.size(); i++) {
vArray = split_first(configs[i], "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
itemVal = trim(vArray[1]);
switch (hash_(itemName)) {
case "password"_hash:
password = itemVal;
break;
case "sni"_hash:
sni = itemVal;
break;
case "skip-cert-verify"_hash:
scv = itemVal;
break;
case "fingerprint"_hash:
fp = itemVal;
break;
case "tls13"_hash:
tls13 = itemVal;
break;
default:
continue;
}
}
anyTlSConstruct(node, ANYTLS_DEFAULT_GROUP, remarks, port, password, server,
std::vector<std::string>{}, fp, sni,
udp, tribool(), scv, tribool(), "", 30, 30, 0);
break;
default:
switch (hash_(remarks)) {
case "shadowsocks"_hash: //quantumult x style ss/ssr link
@@ -2404,7 +2455,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
continue;
for (i = 1; i < configs.size(); i++) {
vArray = split(trim(configs[i]), "=");
vArray = split_first(trim(configs[i]), "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2499,7 +2550,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
net = "tcp";
for (i = 1; i < configs.size(); i++) {
vArray = split(trim(configs[i]), "=");
vArray = split_first(trim(configs[i]), "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2566,7 +2617,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
net = "tcp";
for (i = 1; i < configs.size(); i++) {
vArray = split(trim(configs[i]), "=");
vArray = split_first(trim(configs[i]), "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2632,7 +2683,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
continue;
for (i = 1; i < configs.size(); i++) {
vArray = split(trim(configs[i]), "=");
vArray = split_first(trim(configs[i]), "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
@@ -2684,7 +2735,7 @@ bool explodeSurge(std::string surge, std::vector<Proxy> &nodes) {
continue;
for (i = 1; i < configs.size(); i++) {
vArray = split(trim(configs[i]), "=");
vArray = split_first(trim(configs[i]), "=");
if (vArray.size() != 2)
continue;
itemName = trim(vArray[0]);
+16
View File
@@ -25,6 +25,22 @@ std::vector<std::string> split(const std::string &s, const std::string &separato
return result;
}
std::vector<std::string> split_first(const std::string &s, const std::string &separator)
{
std::vector<std::string> result;
string_size pos = s.find(separator);
if(pos == std::string::npos)
{
result.push_back(s);
}
else
{
result.push_back(s.substr(0, pos));
result.push_back(s.substr(pos + separator.size()));
}
return result;
}
void split(std::vector<std::string_view> &result, std::string_view s, char separator)
{
string_size bpos = 0, epos = s.find(separator);
+2
View File
@@ -18,6 +18,8 @@ using string_pair_array = std::vector<std::pair<std::string, std::string>>;
std::vector<std::string> split(const std::string &s, const std::string &separator);
std::vector<std::string_view> split(std::string_view s, char separator);
void split(std::vector<std::string_view> &result, std::string_view s, char separator);
// Split on first occurrence only (preserves values containing separator, e.g. base64 "==")
std::vector<std::string> split_first(const std::string &s, const std::string &separator);
std::string join(const string_array &arr, const std::string &delimiter);
template <typename InputIt>