Merge pull request #10 from VizzleTF/main

Add some features
This commit is contained in:
itdoginfo
2024-12-12 22:15:51 +03:00
committed by GitHub
11 changed files with 816 additions and 436 deletions

View File

@@ -21,11 +21,38 @@ return view.extend({
o.value('proxy', ('Proxy'));
o.ucisection = 'main';
o = s.taboption('basic', form.TextValue, 'proxy_string', _('Proxy Configuration URL'), _('Enter connection string starting with vless:// or ss:// for proxy configuration'));
o = s.taboption('basic', form.ListValue, 'proxy_config_type', _('Configuration Type'), _('Select how to configure the proxy'));
o.value('url', _('Connection URL'));
o.value('outbound', _('Outbound Config'));
o.default = 'url';
o.depends('mode', 'proxy');
o.ucisection = 'main';
o = s.taboption('basic', form.TextValue, 'proxy_string', _('Proxy Configuration URL'), _('Enter connection string starting with vless:// or ss:// for proxy configuration'));
o.depends('proxy_config_type', 'url');
o.rows = 5;
o.ucisection = 'main';
o = s.taboption('basic', form.TextValue, 'outbound_json', _('Outbound Configuration'), _('Enter complete outbound configuration in JSON format'));
o.depends('proxy_config_type', 'outbound');
o.rows = 10;
o.ucisection = 'main';
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
try {
const parsed = JSON.parse(value);
if (!parsed.type || !parsed.server || !parsed.server_port) {
return _('JSON must contain at least type, server and server_port fields');
}
return true;
} catch (e) {
return _('Invalid JSON format');
}
};
o = s.taboption('basic', form.ListValue, 'interface', _('Network Interface'), _('Select network interface for VPN connection'));
o.depends('mode', 'vpn');
o.ucisection = 'main';
@@ -88,14 +115,17 @@ return view.extend({
o.rmempty = false;
o.ucisection = 'main';
o = s.taboption('basic', form.Flag, 'custom_domains_list_enabled', _('User Domain List'), _('Enable and manage your custom list of domains for selective routing'));
o.default = '0';
o = s.taboption('basic', form.ListValue, 'custom_domains_list_enabled', _('User Domain List Type'), _('Select how to add your custom domains'));
o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List'));
o.value('text', _('Text List'));
o.default = 'disabled';
o.rmempty = false;
o.ucisection = 'main';
o = s.taboption('basic', form.DynamicList, 'custom_domains', _('User Domains'), _('Enter domain names without protocols (example: sub.example.com or example.com)'));
o.placeholder = 'Domains list';
o.depends('custom_domains_list_enabled', '1');
o.depends('custom_domains_list_enabled', 'dynamic');
o.rmempty = false;
o.ucisection = 'main';
o.validate = function (section_id, value) {
@@ -111,6 +141,31 @@ return view.extend({
return true;
};
o = s.taboption('basic', form.TextValue, 'custom_domains_text', _('User Domains List'), _('Enter domain names separated by comma, space or newline (example: sub.example.com, example.com or one domain per line)'));
o.placeholder = 'example.com, sub.example.com\ndomain.com test.com\nsubdomain.domain.com another.com, third.com';
o.depends('custom_domains_list_enabled', 'text');
o.rows = 10;
o.rmempty = false;
o.ucisection = 'main';
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
const domains = value.split(/[,\s\n]/)
.map(d => d.trim())
.filter(d => d.length > 0);
const domainRegex = /^(?!-)[A-Za-z0-9-]+([-.][A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
for (const domain of domains) {
if (!domainRegex.test(domain)) {
return _('Invalid domain format: ' + domain + '. Enter domain without protocol');
}
}
return true;
};
o = s.taboption('basic', form.Flag, 'custom_download_domains_list_enabled', _('Remote Domain Lists'), _('Download and use domain lists from remote URLs'));
o.default = '0';
o.rmempty = false;
@@ -137,14 +192,18 @@ return view.extend({
}
};
o = s.taboption('basic', form.Flag, 'custom_subnets_list_enabled', _('User Subnet List'), _('Enable and manage your custom list of IP subnets for selective routing'));
o.default = '0';
o = s.taboption('basic', form.ListValue, 'custom_subnets_list_enabled', _('User Subnet List Type'), _('Select how to add your custom subnets'));
o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List'));
o.value('text', _('Text List (comma/space/newline separated)'));
o.default = 'disabled';
o.rmempty = false;
o.ucisection = 'main';
o = s.taboption('basic', form.DynamicList, 'custom_subnets', _('User Subnets'), _('Enter subnet in CIDR notation (example: 103.21.244.0/22)'));
o.placeholder = 'Subnets list';
o.depends('custom_subnets_list_enabled', '1');
o = s.taboption('basic', form.DynamicList, 'custom_subnets', _('User Subnets'), _('Enter subnets in CIDR notation (example: 103.21.244.0/22) or single IP addresses'));
o.placeholder = 'IP or subnet';
o.depends('custom_subnets_list_enabled', 'dynamic');
o.rmempty = false;
o.ucisection = 'main';
o.validate = function (section_id, value) {
@@ -152,15 +211,15 @@ return view.extend({
return true;
}
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/;
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/;
if (!subnetRegex.test(value)) {
return _('Invalid subnet format. Use format: X.X.X.X/Y (like 103.21.244.0/22)');
return _('Invalid format. Use format: X.X.X.X or X.X.X.X/Y');
}
// Разбираем IP и маску
const [ip, cidr] = value.split('/');
const ipParts = ip.split('.');
const cidrNum = parseInt(cidr);
for (const part of ipParts) {
const num = parseInt(part);
@@ -169,13 +228,59 @@ return view.extend({
}
}
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32');
if (cidr !== undefined) {
const cidrNum = parseInt(cidr);
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32');
}
}
return true;
};
o = s.taboption('basic', form.TextValue, 'custom_subnets_text', _('User Subnets List'), _('Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline'));
o.placeholder = '103.21.244.0/22\n8.8.8.8\n1.1.1.1/32, 9.9.9.9 10.10.10.10';
o.depends('custom_subnets_list_enabled', 'text');
o.rows = 10;
o.rmempty = false;
o.ucisection = 'main';
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
// Split by commas, spaces and newlines
const subnets = value.split(/[,\s\n]/)
.map(s => s.trim())
.filter(s => s.length > 0);
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/;
for (const subnet of subnets) {
if (!subnetRegex.test(subnet)) {
return _('Invalid format: ' + subnet + '. Use format: X.X.X.X or X.X.X.X/Y');
}
const [ip, cidr] = subnet.split('/');
const ipParts = ip.split('.');
for (const part of ipParts) {
const num = parseInt(part);
if (num < 0 || num > 255) {
return _('IP parts must be between 0 and 255 in: ' + subnet);
}
}
if (cidr !== undefined) {
const cidrNum = parseInt(cidr);
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32 in: ' + subnet);
}
}
}
return true;
};
o = s.taboption('basic', form.Flag, 'custom_download_subnets_list_enabled', _('Remote Subnet Lists'), _('Download and use subnet lists from remote URLs'));
o.default = '0';
o.rmempty = false;
@@ -315,10 +420,38 @@ return view.extend({
o.depends('second_enable', '1');
o.ucisection = 'second';
o = s.taboption('secondary_config', form.TextValue, 'second_proxy_string', _('Proxy Configuration URL'), _('Enter connection string starting with vless:// or ss:// for proxy configuration'));
o = s.taboption('secondary_config', form.ListValue, 'second_proxy_config_type', _('Configuration Type'), _('Select how to configure the proxy'));
o.value('url', _('Connection URL'));
o.value('outbound', _('Outbound Config'));
o.default = 'url';
o.depends('second_mode', 'proxy');
o.ucisection = 'second';
o = s.taboption('secondary_config', form.TextValue, 'second_proxy_string', _('Proxy Configuration URL'), _('Enter connection string starting with vless:// or ss:// for proxy configuration'));
o.depends('second_proxy_config_type', 'url');
o.rows = 5;
o.ucisection = 'second';
o = s.taboption('secondary_config', form.TextValue, 'second_outbound_json', _('Outbound Configuration'), _('Enter complete outbound configuration in JSON format'));
o.depends('second_proxy_config_type', 'outbound');
o.rows = 10;
o.ucisection = 'second';
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
try {
const parsed = JSON.parse(value);
if (!parsed.type || !parsed.server || !parsed.server_port) {
return _('JSON must contain at least type, server and server_port fields');
}
return true;
} catch (e) {
return _('Invalid JSON format');
}
};
o = s.taboption('secondary_config', form.ListValue, 'second_interface', _('Network Interface'), _('Select network interface for VPN connection'));
o.depends('second_mode', 'vpn');
o.ucisection = 'second';
@@ -354,15 +487,18 @@ return view.extend({
o.rmempty = false;
o.ucisection = 'second';
o = s.taboption('secondary_config', form.Flag, 'second_custom_domains_list_enabled', _('User Domain List'), _('Enable and manage your custom list of domains for selective routing'));
o.default = '0';
o = s.taboption('secondary_config', form.ListValue, 'second_custom_domains_list_enabled', _('User Domain List Type'), _('Select how to add your custom domains'));
o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List'));
o.value('text', _('Text List'));
o.default = 'disabled';
o.rmempty = false;
o.depends('second_enable', '1');
o.ucisection = 'second';
o = s.taboption('secondary_config', form.DynamicList, 'second_custom_domains', _('User Domains'), _('Enter domain names without protocols (example: sub.example.com or example.com)'));
o.placeholder = 'Domains list';
o.depends('second_custom_domains_list_enabled', '1');
o.depends('second_custom_domains_list_enabled', 'dynamic');
o.rmempty = false;
o.ucisection = 'second';
o.validate = function (section_id, value) {
@@ -378,15 +514,10 @@ return view.extend({
return true;
};
o = s.taboption('secondary_config', form.Flag, 'second_custom_subnets_list_enabled', _('User Subnet List'), _('Enable and manage your custom list of IP subnets for selective routing'));
o.default = '0';
o.rmempty = false;
o.depends('second_enable', '1');
o.ucisection = 'second';
o = s.taboption('secondary_config', form.DynamicList, 'second_custom_subnets', _('User Subnets'), _('Enter subnet in CIDR notation (example: 103.21.244.0/22)'));
o.placeholder = 'Subnets list';
o.depends('second_custom_subnets_list_enabled', '1');
o = s.taboption('secondary_config', form.TextValue, 'second_custom_domains_text', _('User Domains List'), _('Enter domain names separated by comma, space or newline (example: sub.example.com, example.com or one domain per line)'));
o.placeholder = 'example.com, sub.example.com\ndomain.com test.com\nsubdomain.domain.com another.com, third.com';
o.depends('second_custom_domains_list_enabled', 'text');
o.rows = 10;
o.rmempty = false;
o.ucisection = 'second';
o.validate = function (section_id, value) {
@@ -394,15 +525,47 @@ return view.extend({
return true;
}
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/;
const domains = value.split(/[,\s\n]/)
.map(d => d.trim())
.filter(d => d.length > 0);
const domainRegex = /^(?!-)[A-Za-z0-9-]+([-.][A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
for (const domain of domains) {
if (!domainRegex.test(domain)) {
return _('Invalid domain format: ' + domain + '. Enter domain without protocol');
}
}
return true;
};
o = s.taboption('secondary_config', form.ListValue, 'second_custom_subnets_list_enabled', _('User Subnet List Type'), _('Select how to add your custom subnets'));
o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List'));
o.value('text', _('Text List'));
o.default = 'disabled';
o.rmempty = false;
o.depends('second_enable', '1');
o.ucisection = 'second';
o = s.taboption('secondary_config', form.DynamicList, 'second_custom_subnets', _('User Subnets'), _('Enter subnets in CIDR notation (example: 103.21.244.0/22) or single IP addresses'));
o.placeholder = 'IP or subnet';
o.depends('second_custom_subnets_list_enabled', 'dynamic');
o.rmempty = false;
o.ucisection = 'second';
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/;
if (!subnetRegex.test(value)) {
return _('Invalid subnet format. Use format: X.X.X.X/Y (like 103.21.244.0/22)');
return _('Invalid format. Use format: X.X.X.X or X.X.X.X/Y');
}
const [ip, cidr] = value.split('/');
const ipParts = ip.split('.');
const cidrNum = parseInt(cidr);
for (const part of ipParts) {
const num = parseInt(part);
@@ -411,13 +574,58 @@ return view.extend({
}
}
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32');
if (cidr !== undefined) {
const cidrNum = parseInt(cidr);
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32');
}
}
return true;
};
o = s.taboption('secondary_config', form.TextValue, 'second_custom_subnets_text', _('User Subnets List'), _('Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline'));
o.placeholder = '103.21.244.0/22\n8.8.8.8\n1.1.1.1/32, 9.9.9.9 10.10.10.10';
o.depends('second_custom_subnets_list_enabled', 'text');
o.rows = 10;
o.rmempty = false;
o.ucisection = 'second';
o.validate = function (section_id, value) {
if (!value || value.length === 0) {
return true;
}
const subnets = value.split(/[,\s\n]/)
.map(s => s.trim())
.filter(s => s.length > 0);
const subnetRegex = /^(\d{1,3}\.){3}\d{1,3}(\/\d{1,2})?$/;
for (const subnet of subnets) {
if (!subnetRegex.test(subnet)) {
return _('Invalid format: ' + subnet + '. Use format: X.X.X.X or X.X.X.X/Y');
}
const [ip, cidr] = subnet.split('/');
const ipParts = ip.split('.');
for (const part of ipParts) {
const num = parseInt(part);
if (num < 0 || num > 255) {
return _('IP parts must be between 0 and 255 in: ' + subnet);
}
}
if (cidr !== undefined) {
const cidrNum = parseInt(cidr);
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32 in: ' + subnet);
}
}
}
return true;
};
return m.render();
}
});

View File

@@ -219,3 +219,75 @@ msgstr "CIDR должен быть между 0 и 32"
msgid "Invalid IP format. Use format: X.X.X.X (like 192.168.1.1)"
msgstr "Неверный формат IP. Используйте формат: X.X.X.X (например: 192.168.1.1)"
msgid "User Domain List Type"
msgstr "Тип пользовательского списка доменов"
msgid "Select how to add your custom domains"
msgstr "Выберите способ добавления пользовательских доменов"
msgid "Disabled"
msgstr "Отключено"
msgid "Dynamic List"
msgstr "Динамический список"
msgid "Text List"
msgstr "Текстовый список"
msgid "User Domains List"
msgstr "Список пользовательских доменов"
msgid "Enter domain names separated by comma, space or newline (example: sub.example.com, example.com or one domain per line)"
msgstr "Введите имена доменов через запятую, пробел или новую строку (пример: sub.example.com, example.com или один домен на строку)"
msgid "Invalid domain format: %s. Enter domain without protocol"
msgstr "Неверный формат домена: %s. Введите домен без протокола"
msgid "User Subnet List Type"
msgstr "Тип пользовательского списка подсетей"
msgid "Select how to add your custom subnets"
msgstr "Выберите способ добавления пользовательских подсетей"
msgid "Text List (comma/space/newline separated)"
msgstr "Текстовый список (разделенный запятыми/пробелами/новыми строками)"
msgid "Enter subnets in CIDR notation (example: 103.21.244.0/22) or single IP addresses"
msgstr "Введите подсети в нотации CIDR (пример: 103.21.244.0/22) или отдельные IP-адреса"
msgid "User Subnets List"
msgstr "Список пользовательских подсетей"
msgid "Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline"
msgstr "Введите подсети в нотации CIDR или отдельные IP-адреса через запятую, пробел или новую строку"
msgid "Invalid format. Use format: X.X.X.X or X.X.X.X/Y"
msgstr "Неверный формат. Используйте формат: X.X.X.X или X.X.X.X/Y"
msgid "IP parts must be between 0 and 255 in: %s"
msgstr "Части IP-адреса должны быть между 0 и 255 в: %s"
msgid "Configuration Type"
msgstr "Тип конфигурации"
msgid "Select how to configure the proxy"
msgstr "Выберите способ настройки прокси"
msgid "Connection URL"
msgstr "URL подключения"
msgid "Outbound Config"
msgstr "Конфигурация Outbound"
msgid "Outbound Configuration"
msgstr "Конфигурация исходящего соединения"
msgid "Enter complete outbound configuration in JSON format"
msgstr "Введите полную конфигурацию исходящего соединения в формате JSON"
msgid "JSON must contain at least type, server and server_port fields"
msgstr "JSON должен содержать как минимум поля type, server и server_port"
msgid "Invalid JSON format"
msgstr "Неверный формат JSON"

View File

@@ -219,3 +219,75 @@ msgstr ""
msgid "Invalid IP format. Use format: X.X.X.X (like 192.168.1.1)"
msgstr ""
msgid "User Domain List Type"
msgstr ""
msgid "Select how to add your custom domains"
msgstr ""
msgid "Disabled"
msgstr ""
msgid "Dynamic List"
msgstr ""
msgid "Text List"
msgstr ""
msgid "User Domains List"
msgstr ""
msgid "Enter domain names separated by comma, space or newline (example: sub.example.com, example.com or one domain per line)"
msgstr ""
msgid "Invalid domain format: %s. Enter domain without protocol"
msgstr ""
msgid "User Subnet List Type"
msgstr ""
msgid "Select how to add your custom subnets"
msgstr ""
msgid "Text List (comma/space/newline separated)"
msgstr ""
msgid "Enter subnets in CIDR notation (example: 103.21.244.0/22) or single IP addresses"
msgstr ""
msgid "User Subnets List"
msgstr ""
msgid "Enter subnets in CIDR notation or single IP addresses, separated by comma, space or newline"
msgstr ""
msgid "Invalid format. Use format: X.X.X.X or X.X.X.X/Y"
msgstr ""
msgid "IP parts must be between 0 and 255 in: %s"
msgstr ""
msgid "Configuration Type"
msgstr ""
msgid "Select how to configure the proxy"
msgstr ""
msgid "Connection URL"
msgstr ""
msgid "Outbound Config"
msgstr ""
msgid "Outbound Configuration"
msgstr ""
msgid "Enter complete outbound configuration in JSON format"
msgstr ""
msgid "JSON must contain at least type, server and server_port fields"
msgstr ""
msgid "Invalid JSON format"
msgstr ""

View File

@@ -50,9 +50,6 @@ define Package/podkop/install
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/etc/config/podkop $(1)/etc/config/podkop
$(INSTALL_DIR) $(1)/etc/podkop
$(INSTALL_DATA) ./files/etc/podkop/* $(1)/etc/podkop/
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_DATA) ./files/etc/hotplug.d/iface/50-podkop $(1)/etc/hotplug.d/iface/50-podkop
endef

View File

@@ -1,19 +1,23 @@
config main 'main'
option mode ''
option interface ''
option proxy_string ''
option proxy_config_type ''
#option outbound_json ''
#option proxy_string ''
option domain_list_enabled '1'
option domain_list 'ru_inside'
option subnets_list_enabled '0'
#list subnets 'twitter'
option custom_domains_list_enabled '0'
option custom_domains_list_type 'disable'
#list custom_domains ''
#option custom_domains_text ''
option custom_local_domains_list_enabled '0'
#list custom_local_domains ''
option custom_download_domains_list_enabled '0'
#list custom_download_domains ''
option custom_subnets_list_enabled '0'
option custom_domains_list_type 'disable'
#list custom_subnets ''
#custom_subnets_text ''
option custom_download_subnets_list_enabled '0'
#list custom_download_subnets ''
option all_traffic_from_ip_enabled '0'
@@ -26,15 +30,20 @@ config main 'main'
option socks5 '0'
option exclude_ntp '0'
option update_interval ''
option custom_domains_text
config second 'second'
option second_enable '0'
option second_mode 'proxy'
option second_interface ''
option second_proxy_string ''
option second_proxy_config_type ''
#option second_outbound_json ''
#option second_proxy_string ''
option second_domain_service_enabled '0'
#list second_service_list 'youtube'
option second_custom_domains_list_enabled '0'
option second_custom_domains_type 'disable'
#list second_custom_domains 'ifconfig.io'
option second_custom_subnets_list_enabled '0'
#option second_custom_domains_text ''
option second_custom_subnets_type 'disable'
#list second_custom_subnets ''
#porion second_custom_subnets_text ''

View File

@@ -37,14 +37,27 @@ start_service() {
config_get_bool second_enable "second" "second_enable" "0"
config_get second_mode "second" "second_mode" "0"
if [ "$second_enable" -eq "1" ] && [ "$second_mode" = "proxy" ]; then
config_get proxy_string "second" "second_proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1603"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1603"
config_get proxy_config_type "second" "second_proxy_config_type"
if [ "$proxy_config_type" = "outbound" ]; then
config_get outbound_json "second" "second_outbound_json"
if [ -n "$outbound_json" ]; then
log "Using JSON outbound configuration for second proxy"
sing_box_config_outbound_json "$outbound_json" "1603"
else
log "Missing outbound JSON configuration"
return
fi
else
log "Unsupported proxy type: $proxy_string"
return
config_get proxy_string "second" "second_proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1603"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1603"
else
log "Unsupported proxy type or missing configuration"
return
fi
fi
add_route_tproxy podkop2
sing_box_config_check
@@ -78,28 +91,95 @@ start_service() {
outbound_main=$(mktemp)
outbound_second=$(mktemp)
config_get proxy_string main "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_outbound_shadowsocks "$proxy_string" "$outbound_main" main
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_outbound_vless "$proxy_string" "$outbound_main" main
# Main proxy config
config_get proxy_config_type main "proxy_config_type"
if [ "$proxy_config_type" = "outbound" ]; then
config_get outbound_json main "outbound_json"
if [ -n "$outbound_json" ]; then
echo '{"outbounds":[' > "$outbound_main"
echo "$outbound_json" | jq '. + {tag: "main"}' >> "$outbound_main"
echo ']}' >> "$outbound_main"
else
log "Missing main outbound JSON configuration"
rm -f "$outbound_main" "$outbound_second"
return
fi
else
log "Unsupported proxy type: $proxy_string"
return
config_get proxy_string main "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1602"
jq '.outbounds[0] + {tag: "main"} | {outbounds: [.]}' /etc/sing-box/config.json > "$outbound_main"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1602"
jq '.outbounds[0] + {tag: "main"} | {outbounds: [.]}' /etc/sing-box/config.json > "$outbound_main"
else
log "Unsupported proxy type or missing configuration for main"
rm -f "$outbound_main" "$outbound_second"
return
fi
fi
config_get proxy_string "second" "second_proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_outbound_shadowsocks "$proxy_string" "$outbound_second" second
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_outbound_vless "$proxy_string" "$outbound_second" second
# Second proxy config
config_get proxy_config_type second "second_proxy_config_type"
if [ "$proxy_config_type" = "outbound" ]; then
config_get outbound_json second "second_outbound_json"
if [ -n "$outbound_json" ]; then
echo '{"outbounds":[' > "$outbound_second"
echo "$outbound_json" | jq '. + {tag: "second"}' >> "$outbound_second"
echo ']}' >> "$outbound_second"
else
log "Missing second outbound JSON configuration"
rm -f "$outbound_main" "$outbound_second"
return
fi
else
log "Unsupported proxy type: $proxy_string"
return
config_get proxy_string "second" "second_proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1603"
jq '.outbounds[0] + {tag: "second"} | {outbounds: [.]}' /etc/sing-box/config.json > "$outbound_second"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1603"
jq '.outbounds[0] + {tag: "second"} | {outbounds: [.]}' /etc/sing-box/config.json > "$outbound_second"
else
log "Unsupported proxy type or missing configuration for second"
rm -f "$outbound_main" "$outbound_second"
return
fi
fi
jq --argjson outbounds "$(jq -s '{"outbounds": (.[0].outbounds + .[1].outbounds)}' "$outbound_main" "$outbound_second")" \
'.outbounds += $outbounds.outbounds' /etc/podkop/sing-box-two-proxy-template.json >/etc/sing-box/config.json
jq -s '{
"log": {"level": "warn"},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": 1602,
"sniff": false,
"tag": "main"
},
{
"type": "tproxy",
"listen": "::",
"listen_port": 1603,
"sniff": false,
"tag": "second"
}
],
"outbounds": (.[0].outbounds + .[1].outbounds),
"route": {
"rules": [
{
"inbound": "main",
"outbound": "main"
},
{
"inbound": "second",
"outbound": "second"
}
],
"auto_detect_interface": true
}
}' "$outbound_main" "$outbound_second" > /etc/sing-box/config.json
rm -f "$outbound_main" "$outbound_second"
@@ -111,14 +191,27 @@ start_service() {
config_get_bool second_enable "second" "second_enable" "0"
config_get second_mode "second" "second_mode" "0"
if [ "$second_enable" -eq "0" ] || [ "$second_mode" = "vpn" ]; then
config_get proxy_string main "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1602"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1602"
config_get proxy_config_type main "proxy_config_type"
if [ "$proxy_config_type" = "outbound" ]; then
config_get outbound_json main "outbound_json"
if [ -n "$outbound_json" ]; then
log "Using JSON outbound configuration"
sing_box_config_outbound_json "$outbound_json" "1602"
else
log "Missing outbound JSON configuration"
return
fi
else
log "Unsupported proxy type: $proxy_string"
return
config_get proxy_string main "proxy_string"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1602"
elif [[ "$proxy_string" =~ ^vless:// ]]; then
sing_box_config_vless "$proxy_string" "1602"
else
log "Unsupported proxy type or missing configuration"
return
fi
fi
add_route_tproxy podkop
fi
@@ -274,6 +367,7 @@ remove_cron_job() {
}
list_update() {
# Main domains processing
config_get_bool domain_list_enabled "main" "domain_list_enabled" "0"
if [ "$domain_list_enabled" -eq 1 ]; then
log "Adding a common domains list"
@@ -283,15 +377,24 @@ list_update() {
dnsmasq_config_check podkop-domains.lst
fi
config_get_bool custom_domains_list_enabled "main" "custom_domains_list_enabled" "0"
if [ "$custom_domains_list_enabled" -eq 1 ]; then
# Main custom domains processing
config_get custom_domains_list_type "main" "custom_domains_list_enabled" "disabled"
if [ "$custom_domains_list_type" != "disabled" ]; then
log "Adding a custom domains list"
add_set "podkop_domains" "main"
rm -f /tmp/dnsmasq.d/podkop-custom-domains.lst
config_list_foreach main custom_domains "list_custom_domains_create" "podkop"
if [ "$custom_domains_list_type" = "dynamic" ]; then
config_list_foreach main custom_domains "list_custom_domains_create" "podkop"
elif [ "$custom_domains_list_type" = "text" ]; then
config_get custom_domains_text main "custom_domains_text"
process_domains_text "$custom_domains_text" "podkop"
fi
dnsmasq_config_check podkop-custom-domains.lst
fi
# Main custom download domains
config_get_bool custom_download_domains_list_enabled "main" "custom_download_domains_list_enabled" "0"
if [ "$custom_download_domains_list_enabled" -eq 1 ]; then
log "Adding a custom domains list from URL"
@@ -299,6 +402,7 @@ list_update() {
config_list_foreach main custom_download_domains "list_custom_download_domains_create" "podkop"
fi
# Main domains delist
config_get_bool custom_local_domains_list_enabled "main" "custom_local_domains_list_enabled" "0"
if [ "$custom_local_domains_list_enabled" -eq 1 ]; then
log "Adding a custom local domain list"
@@ -313,20 +417,56 @@ list_update() {
dnsmasq_config_check podkop-domains.lst
fi
if [ "$domain_list_enabled" -eq 1 ] || [ "$custom_domains_list_enabled" -eq 1 ]; then
/etc/init.d/dnsmasq restart
# Main subnets processing
config_get_bool subnets_list_enabled "main" "subnets_list_enabled" "0"
if [ "$subnets_list_enabled" -eq 1 ]; then
log "Adding a subnets from list"
mkdir -p /tmp/podkop
add_set "podkop_subnets" "main"
config_list_foreach main subnets "list_subnets_download"
fi
config_get_bool second_custom_domains_list_enabled "second" "second_custom_domains_list_enabled" "0"
if [ "$second_custom_domains_list_enabled" -eq 1 ]; then
# Main custom subnets
config_get custom_subnets_list_type "main" "custom_subnets_list_enabled" "disabled"
if [ "$custom_subnets_list_type" != "disabled" ]; then
log "Adding a custom subnets list"
add_set "podkop_subnets" "main"
if [ "$custom_subnets_list_type" = "dynamic" ]; then
config_list_foreach main custom_subnets list_custom_subnets_preprocess "podkop"
elif [ "$custom_subnets_list_type" = "text" ]; then
config_get custom_subnets_text main "custom_subnets_text"
process_subnets_text "$custom_subnets_text" "podkop"
fi
fi
# Main custom download subnets
config_get_bool custom_download_subnets_list_enabled "main" "custom_download_subnets_list_enabled" "0"
if [ "$custom_download_subnets_list_enabled" -eq 1 ]; then
log "Adding a subnets from URL"
mkdir -p /tmp/podkop
add_set "podkop_subnets" "main"
config_list_foreach main custom_download_subnets "list_subnets_download"
fi
# Second custom domains processing
config_get second_custom_domains_list_type "second" "second_custom_domains_list_enabled" "disabled"
if [ "$second_custom_domains_list_type" != "disabled" ]; then
log "Adding a custom domains list. Second podkop"
add_set "podkop2_domains" "second"
rm -f /tmp/dnsmasq.d/podkop2-custom-domains.lst
config_list_foreach second second_custom_domains "list_delist_domains"
config_list_foreach second second_custom_domains "list_custom_domains_create" "podkop2"
if [ "$second_custom_domains_list_type" = "dynamic" ]; then
config_list_foreach second second_custom_domains "list_custom_domains_create" "podkop2"
elif [ "$second_custom_domains_list_type" = "text" ]; then
config_get second_custom_domains_text second "second_custom_domains_text"
process_domains_text "$second_custom_domains_text" "podkop2"
fi
dnsmasq_config_check podkop2-custom-domains.lst
fi
# Second service domains
config_get_bool second_domain_service_enabled "second" "second_domain_service_enabled" "0"
if [ "$second_domain_service_enabled" -eq 1 ]; then
log "Adding a service for podkop2"
@@ -337,38 +477,26 @@ list_update() {
dnsmasq_config_check podkop2-domains.lst
fi
if [ "$second_custom_domains_list_enabled" -eq 1 ] || [ "$second_domain_service_enabled" -eq 1 ]; then
/etc/init.d/dnsmasq restart
fi
config_get_bool subnets_list_enabled "main" "subnets_list_enabled" "0"
if [ "$subnets_list_enabled" -eq 1 ]; then
log "Adding a subnets from list"
mkdir -p /tmp/podkop
add_set "podkop_subnets" "main"
config_list_foreach main subnets "list_subnets_download"
fi
config_get_bool custom_download_subnets_list_enabled "main" "custom_download_subnets_list_enabled" "0"
if [ "$custom_download_subnets_list_enabled" -eq 1 ]; then
log "Adding a subnets from URL"
mkdir -p /tmp/podkop
add_set "podkop_subnets" "main"
config_list_foreach main custom_download_subnets "list_subnets_download"
fi
config_get_bool custom_subnets_list_enabled "main" "custom_subnets_list_enabled" "0"
if [ "$custom_subnets_list_enabled" -eq 1 ]; then
log "Adding a custom subnets list"
add_set "podkop_subnets" "main"
config_list_foreach main custom_subnets "list_custom_subnets_create" "podkop"
fi
config_get_bool second_custom_subnets_list_enabled "second" "second_custom_subnets_list_enabled" "0"
if [ "$second_custom_subnets_list_enabled" -eq 1 ]; then
# Second custom subnets
config_get second_custom_subnets_list_type "second" "second_custom_subnets_list_enabled" "disabled"
if [ "$second_custom_subnets_list_type" != "disabled" ]; then
log "Adding a custom subnets list. Second"
add_set "podkop2_subnets" "second"
config_list_foreach second second_custom_subnets "list_custom_subnets_create" "podkop2"
if [ "$second_custom_subnets_list_type" = "dynamic" ]; then
config_list_foreach second second_custom_subnets list_custom_subnets_preprocess "podkop2"
elif [ "$second_custom_subnets_list_type" = "text" ]; then
config_get second_custom_subnets_text second "second_custom_subnets_text"
process_subnets_text "$second_custom_subnets_text" "podkop2"
fi
fi
# Restart dnsmasq if needed
if [ "$domain_list_enabled" -eq 1 ] || [ "$custom_domains_list_type" != "disabled" ] || \
[ "$custom_download_domains_list_enabled" -eq 1 ] || \
[ "$second_custom_domains_list_type" != "disabled" ] || \
[ "$second_domain_service_enabled" -eq 1 ]; then
/etc/init.d/dnsmasq restart
fi
}
@@ -745,6 +873,34 @@ dnsmasq_config_check() {
fi
}
sing_box_config_outbound_json() {
local json_config="$1"
local listen_port="$2"
cat > /tmp/base_config.json << EOF
{
"log": {
"level": "warn"
},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": $listen_port,
"sniff": false
}
],
"outbounds": [],
"route": {
"auto_detect_interface": true
}
}
EOF
jq --argjson outbound "$json_config" '.outbounds += [$outbound]' /tmp/base_config.json > /etc/sing-box/config.json
rm -f /tmp/base_config.json
}
sing_box_uci() {
local config="/etc/config/sing-box"
if grep -q "option enabled '0'" "$config" ||
@@ -762,36 +918,61 @@ sing_box_config_shadowsocks() {
local STRING="$1"
local listen_port="$2"
local encrypted_part=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 --decode)
local method=$(echo "$encrypted_part" | cut -d':' -f1)
local password=$(echo "$encrypted_part" | cut -d':' -f2-)
# Определяем тип SS (2022 или old) по наличию : в base64 части
if echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 -d 2>/dev/null | grep -q ":"; then
# Old SS format
local encrypted_part=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 --decode)
local method=$(echo "$encrypted_part" | cut -d':' -f1)
local password=$(echo "$encrypted_part" | cut -d':' -f2-)
else
# SS 2022 format
local method_and_password=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1)
local method=$(echo "$method_and_password" | cut -d':' -f1)
local password=$(echo "$method_and_password" | cut -d':' -f2- | sed 's/%3D/=/g')
# Если method в base64, декодируем
if echo "$method" | base64 -d &>/dev/null; then
method=$(echo "$method" | base64 -d)
fi
fi
local server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
local port=$(echo "$STRING" | sed -n 's|.*:\([0-9]\+\).*|\1|p')
local label=$(echo "$STRING" | cut -d'#' -f2)
template_config="/etc/podkop/sing-box-shadowsocks-template.json"
# Create base config
cat > /tmp/ss_config.json << EOF
{
"log": {
"level": "warn"
},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": $listen_port,
"sniff": false
}
],
"outbounds": [
{
"type": "shadowsocks",
"server": "$server",
"server_port": $port,
"method": "$method",
"password": "$password",
"udp_over_tcp": {
"enabled": true,
"version": 2
}
}
],
"route": {
"auto_detect_interface": true
}
}
EOF
jq --arg server "$server" \
--arg port "$port" \
--arg method "$method" \
--arg password "$password" \
--arg listen_port "$listen_port" \
'.inbounds[] |=
if .type == "tproxy" then
.listen_port = ($listen_port | tonumber)
else
.
end |
.outbounds[] |=
if .type == "shadowsocks" then
.server = $server |
.server_port = ($port | tonumber) |
.method = $method |
.password = $password
else
.
end' "$template_config" >/etc/sing-box/config.json
mv /tmp/ss_config.json /etc/sing-box/config.json
}
sing_box_config_vless() {
@@ -799,167 +980,106 @@ sing_box_config_vless() {
local listen_port="$2"
get_param() {
echo "$STRING" | sed -n "s/.*[?&]$1=\([^&?#]*\).*/\1/p"
local param="$1"
local value=$(echo "$STRING" | sed -n "s/.*[?&]$param=\([^&?#]*\).*/\1/p")
value=$(echo "$value" | sed 's/%2F/\//g; s/%2C/,/g; s/%3D/=/g; s/%2B/+/g; s/%20/ /g' | tr -d '\n' | tr -d '\r')
echo "$value"
}
uuid=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1)
server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
port=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f2 | cut -d'?' -f1 | awk -F'/' '{print $1}')
uuid=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | tr -d '\n' | tr -d '\r' | sed 's/False//g')
server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1 | tr -d '\n' | tr -d '\r' | sed 's/False//g')
port=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f2 | cut -d'?' -f1 | cut -d'/' -f1 | cut -d'#' -f1 | tr -d '\n' | tr -d '\r' | sed 's/False//g')
type=$(get_param "type")
flow=$(get_param "flow")
sni=$(get_param "sni")
fp=$(get_param "fp")
security=$(get_param "security")
pbk=$(get_param "pbk")
sid=$(get_param "sid")
encoding=$(get_param "packetEncoding")
alpn=$(echo "$(get_param "alpn" | sed 's/%2C/,/g; s/%2F/\//g')" | jq -R -s -c 'split(",")' | sed 's/\\n//g')
label=$(echo "$STRING" | cut -d'#' -f2)
jq -n \
--arg listen_port "$listen_port" \
--arg server "$server" \
--argjson port "$port" \
--arg uuid "$uuid" \
--arg type "$(get_param "type")" \
--arg flow "$(get_param "flow")" \
--arg sni "$(get_param "sni")" \
--arg fp "$(get_param "fp")" \
--arg security "$(get_param "security")" \
--arg pbk "$(get_param "pbk")" \
--arg sid "$(get_param "sid")" \
--arg alpn "$(get_param "alpn")" \
--arg path "$(get_param "path")" \
--arg host "$(get_param "host")" \
--arg spx "$(get_param "spx")" \
--arg insecure "$(get_param "allowInsecure")" \
'{
"log": {
"level": "warn"
},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": ($listen_port|tonumber),
"sniff": false
}
],
"outbounds": [
{
"type": "vless",
"server": $server,
"server_port": ($port|tonumber),
"uuid": $uuid,
"packet_encoding": "",
"domain_strategy": ""
}
],
"route": {
"auto_detect_interface": true
}
} |
template_config="/etc/podkop/sing-box-vless-template.json"
if $flow != "" then .outbounds[0].flow = $flow else . end |
jq --arg server "$server" \
--arg port "$port" \
--arg uuid "$uuid" \
--arg type "$type" \
--arg flow "$flow" \
--arg sni "$sni" \
--arg fp "$fp" \
--arg security "$security" \
--arg pbk "$pbk" \
--arg sid "$sid" \
--argjson alpn "$alpn" \
--arg encoding "$encoding" \
--arg listen_port "$listen_port" \
'.inbounds[] |=
if .type == "tproxy" then
.listen_port = ($listen_port | tonumber)
else
.
end |
.outbounds[] |=
(.server = $server |
.server_port = ($port | tonumber) |
.uuid = $uuid |
if $security == "reality" then
if $flow == "" then del(.flow) else .flow = $flow end |
if $encoding == "" then del(.packet_encoding) else .packet_encoding = $encoding end |
.tls.server_name = $sni |
.tls.utls.fingerprint = $fp |
.tls.reality.public_key = $pbk |
.tls.reality.short_id = $sid
elif $security == "tls" then
.tls.alpn = $alpn |
.tls.server_name = $sni |
del(.flow) |
del(.tls.utls) |
del(.tls.reality)
elif $security == "" or $security == "none" then
del(.flow) |
del(.tls)
else
.
end)' "$template_config" >/etc/sing-box/config.json
}
if $type == "ws" then
.outbounds[0].transport = {
"type": "ws",
"path": $path
} |
if $host != "" then
.outbounds[0].transport.headers = {
"Host": $host
}
else . end
elif $type == "grpc" then
.outbounds[0].transport = {
"type": "grpc"
}
else . end |
sing_box_config_outbound_shadowsocks() {
local STRING="$1"
local outbound="$2"
local name="$3"
if $security == "reality" or $security == "tls" then
.outbounds[0].tls = {
"enabled": true,
"server_name": $sni,
"utls": {
"enabled": true,
"fingerprint": $fp
},
"insecure": ($insecure == "1")
} |
if $alpn != "" then
.outbounds[0].tls.alpn = ($alpn | split(","))
else . end |
if $security == "reality" then
.outbounds[0].tls.reality = {
"enabled": true,
"public_key": $pbk,
"short_id": $sid
}
else . end
else . end' > /etc/sing-box/config.json
local encrypted_part=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 --decode)
local method=$(echo "$encrypted_part" | cut -d':' -f1)
local password=$(echo "$encrypted_part" | cut -d':' -f2-)
local server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
local port=$(echo "$STRING" | cut -d':' -f3 | cut -d'#' -f1)
label=$(echo "$STRING" | cut -d'#' -f2)
template_config="/etc/podkop/sing-box-shadowsocks-outbound-template.json"
jq --arg server "$server" \
--arg port "$port" \
--arg method "$method" \
--arg password "$password" \
--arg tag "$name" \
'.outbounds[] |=
if .type == "shadowsocks" then
.server = $server |
.server_port = ($port | tonumber) |
.method = $method |
.password = $password |
.tag = $tag
else
.
end' "$template_config" >$outbound
}
sing_box_config_outbound_vless() {
local STRING="$1"
local outbound="$2"
local name="$3"
get_param() {
echo "$STRING" | sed -n "s/.*[?&]$1=\([^&?#]*\).*/\1/p"
}
uuid=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1)
server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
port=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f2 | cut -d'?' -f1 | awk -F'/' '{print $1}')
type=$(get_param "type")
flow=$(get_param "flow")
sni=$(get_param "sni")
fp=$(get_param "fp")
security=$(get_param "security")
pbk=$(get_param "pbk")
sid=$(get_param "sid")
alpn=$(echo "$(get_param "alpn" | sed 's/%2C/,/g; s/%2F/\//g')" | jq -R -s -c 'split(",")' | sed 's/\\n//g')
encoding=$(get_param "packetEncoding")
label=$(echo "$STRING" | cut -d'#' -f2)
template_config="/etc/podkop/sing-box-vless-outbound-template.json"
jq --arg server "$server" \
--arg port "$port" \
--arg uuid "$uuid" \
--arg type "$type" \
--arg flow "$flow" \
--arg sni "$sni" \
--arg fp "$fp" \
--arg security "$security" \
--arg pbk "$pbk" \
--arg sid "$sid" \
--argjson alpn "$alpn" \
--arg encoding "$encoding" \
--arg tag "$name" \
'.outbounds[] |=
(.server = $server |
.server_port = ($port | tonumber) |
.uuid = $uuid |
if $security == "reality" then
if $flow == "" then del(.flow) else .flow = $flow end |
if $encoding == "" then del(.packet_encoding) else .packet_encoding = $encoding end |
.tls.server_name = $sni |
.tls.utls.fingerprint = $fp |
.tls.reality.public_key = $pbk |
.tls.reality.short_id = $sid |
.tag = $tag
elif $security == "tls" then
.tls.alpn = $alpn |
.tls.server_name = $sni |
del(.flow) |
del(.tls.utls) |
del(.tls.reality) |
.tag = $tag
elif $security == "" or $security == "none" then
del(.flow) |
del(.tls) |
.tag = $tag
else
.
end)' "$template_config" >$outbound
if [ $? -eq 0 ]; then
echo "Config created successfully"
else
echo "Error: Invalid JSON config generated"
return 1
fi
}
sing_box_config_check() {
@@ -968,3 +1088,50 @@ sing_box_config_check() {
return
fi
}
process_domains_text() {
local text="$1"
local name="$2"
local tmp_file=$(mktemp)
echo "$text" > "$tmp_file"
sed 's/[, ]\+/\n/g' "$tmp_file" | while IFS= read -r domain; do
domain=$(echo "$domain" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [ -n "$domain" ]; then
list_custom_domains_create "$domain" "$name"
fi
done
rm -f "$tmp_file"
}
process_subnets_text() {
local text="$1"
local name="$2"
local tmp_file=$(mktemp)
echo "$text" > "$tmp_file"
sed 's/[, ]\+/\n/g' "$tmp_file" | while IFS= read -r subnet; do
subnet=$(echo "$subnet" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [ -n "$subnet" ]; then
if ! echo "$subnet" | grep -q "/"; then
subnet="$subnet/32"
fi
list_custom_subnets_create "$subnet" "$name"
fi
done
rm -f "$tmp_file"
}
list_custom_subnets_preprocess() {
local subnet="$1"
local name="$2"
if ! echo "$subnet" | grep -q "/"; then
subnet="$subnet/32"
fi
list_custom_subnets_create "$subnet" "$name"
}

View File

@@ -1,16 +0,0 @@
{
"outbounds": [
{
"type": "shadowsocks",
"server": "$HOST",
"server_port": "$PORT",
"method": "$METHOD",
"password": "$PASS",
"udp_over_tcp": {
"enabled": true,
"version": 2
},
"tag": "$TAG"
}
]
}

View File

@@ -1,29 +0,0 @@
{
"log": {
"level": "warn"
},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": 1602,
"sniff": false
}
],
"outbounds": [
{
"type": "shadowsocks",
"server": "$HOST",
"server_port": "$PORT",
"method": "$METHOD",
"password": "$PASS",
"udp_over_tcp": {
"enabled": true,
"version": 2
}
}
],
"route": {
"auto_detect_interface": true
}
}

View File

@@ -1,35 +0,0 @@
{
"log": {
"level": "warn"
},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": 1602,
"sniff": false,
"tag": "main"
},
{
"type": "tproxy",
"listen": "::",
"listen_port": 1603,
"sniff": false,
"tag": "second"
}
],
"outbounds": [],
"route": {
"rules": [
{
"inbound": "main",
"outbound": "main"
},
{
"inbound": "second",
"outbound": "second"
}
],
"auto_detect_interface": true
}
}

View File

@@ -1,26 +0,0 @@
{
"outbounds": [
{
"type": "vless",
"server": "$HOST",
"server_port": "$PORT",
"uuid": "$UUID",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"insecure": false,
"server_name": "$FAKE_SERVER",
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "$PUBLIC_KEY",
"short_id": "$SHORT_ID"
}
},
"tag": "$TAG"
}
]
}

View File

@@ -1,39 +0,0 @@
{
"log": {
"level": "warn"
},
"inbounds": [
{
"type": "tproxy",
"listen": "::",
"listen_port": 1602,
"sniff": false
}
],
"outbounds": [
{
"type": "vless",
"server": "$HOST",
"server_port": "$PORT",
"uuid": "$UUID",
"flow": "xtls-rprx-vision",
"tls": {
"enabled": true,
"insecure": false,
"server_name": "$FAKE_SERVER",
"utls": {
"enabled": true,
"fingerprint": "chrome"
},
"reality": {
"enabled": true,
"public_key": "$PUBLIC_KEY",
"short_id": "$SHORT_ID"
}
}
}
],
"route": {
"auto_detect_interface": true
}
}