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.value('proxy', ('Proxy'));
o.ucisection = 'main'; 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.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.rows = 5;
o.ucisection = 'main'; 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 = s.taboption('basic', form.ListValue, 'interface', _('Network Interface'), _('Select network interface for VPN connection'));
o.depends('mode', 'vpn'); o.depends('mode', 'vpn');
o.ucisection = 'main'; o.ucisection = 'main';
@@ -88,14 +115,17 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o.ucisection = 'main'; 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 = s.taboption('basic', form.ListValue, 'custom_domains_list_enabled', _('User Domain List Type'), _('Select how to add your custom domains'));
o.default = '0'; o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List'));
o.value('text', _('Text List'));
o.default = 'disabled';
o.rmempty = false; o.rmempty = false;
o.ucisection = 'main'; 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 = 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.placeholder = 'Domains list';
o.depends('custom_domains_list_enabled', '1'); o.depends('custom_domains_list_enabled', 'dynamic');
o.rmempty = false; o.rmempty = false;
o.ucisection = 'main'; o.ucisection = 'main';
o.validate = function (section_id, value) { o.validate = function (section_id, value) {
@@ -111,6 +141,31 @@ return view.extend({
return true; 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 = 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.default = '0';
o.rmempty = false; 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.rmempty = false;
o.ucisection = 'main'; 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 = 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 = 'Subnets list'; o.placeholder = 'IP or subnet';
o.depends('custom_subnets_list_enabled', '1'); o.depends('custom_subnets_list_enabled', 'dynamic');
o.rmempty = false; o.rmempty = false;
o.ucisection = 'main'; o.ucisection = 'main';
o.validate = function (section_id, value) { o.validate = function (section_id, value) {
@@ -152,15 +211,15 @@ return view.extend({
return true; 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)) { 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 [ip, cidr] = value.split('/');
const ipParts = ip.split('.'); const ipParts = ip.split('.');
const cidrNum = parseInt(cidr);
for (const part of ipParts) { for (const part of ipParts) {
const num = parseInt(part); const num = parseInt(part);
@@ -169,13 +228,59 @@ return view.extend({
} }
} }
if (cidrNum < 0 || cidrNum > 32) { if (cidr !== undefined) {
return _('CIDR must be between 0 and 32'); const cidrNum = parseInt(cidr);
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32');
}
} }
return true; 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 = 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.default = '0';
o.rmempty = false; o.rmempty = false;
@@ -315,10 +420,38 @@ return view.extend({
o.depends('second_enable', '1'); o.depends('second_enable', '1');
o.ucisection = 'second'; 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.depends('second_mode', 'proxy');
o.ucisection = 'second'; 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 = s.taboption('secondary_config', form.ListValue, 'second_interface', _('Network Interface'), _('Select network interface for VPN connection'));
o.depends('second_mode', 'vpn'); o.depends('second_mode', 'vpn');
o.ucisection = 'second'; o.ucisection = 'second';
@@ -354,15 +487,18 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o.ucisection = 'second'; 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 = s.taboption('secondary_config', form.ListValue, 'second_custom_domains_list_enabled', _('User Domain List Type'), _('Select how to add your custom domains'));
o.default = '0'; o.value('disabled', _('Disabled'));
o.value('dynamic', _('Dynamic List'));
o.value('text', _('Text List'));
o.default = 'disabled';
o.rmempty = false; o.rmempty = false;
o.depends('second_enable', '1'); o.depends('second_enable', '1');
o.ucisection = 'second'; 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 = 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.placeholder = 'Domains list';
o.depends('second_custom_domains_list_enabled', '1'); o.depends('second_custom_domains_list_enabled', 'dynamic');
o.rmempty = false; o.rmempty = false;
o.ucisection = 'second'; o.ucisection = 'second';
o.validate = function (section_id, value) { o.validate = function (section_id, value) {
@@ -378,15 +514,10 @@ return view.extend({
return true; 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 = 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.default = '0'; o.placeholder = 'example.com, sub.example.com\ndomain.com test.com\nsubdomain.domain.com another.com, third.com';
o.rmempty = false; o.depends('second_custom_domains_list_enabled', 'text');
o.depends('second_enable', '1'); o.rows = 10;
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.rmempty = false; o.rmempty = false;
o.ucisection = 'second'; o.ucisection = 'second';
o.validate = function (section_id, value) { o.validate = function (section_id, value) {
@@ -394,15 +525,47 @@ return view.extend({
return true; 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)) { 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 [ip, cidr] = value.split('/');
const ipParts = ip.split('.'); const ipParts = ip.split('.');
const cidrNum = parseInt(cidr);
for (const part of ipParts) { for (const part of ipParts) {
const num = parseInt(part); const num = parseInt(part);
@@ -411,13 +574,58 @@ return view.extend({
} }
} }
if (cidrNum < 0 || cidrNum > 32) { if (cidr !== undefined) {
return _('CIDR must be between 0 and 32'); const cidrNum = parseInt(cidr);
if (cidrNum < 0 || cidrNum > 32) {
return _('CIDR must be between 0 and 32');
}
} }
return true; 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(); return m.render();
} }
}); });

View File

@@ -218,4 +218,76 @@ msgid "CIDR must be between 0 and 32"
msgstr "CIDR должен быть между 0 и 32" msgstr "CIDR должен быть между 0 и 32"
msgid "Invalid IP format. Use format: X.X.X.X (like 192.168.1.1)" 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)" 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

@@ -218,4 +218,76 @@ msgid "CIDR must be between 0 and 32"
msgstr "" msgstr ""
msgid "Invalid IP format. Use format: X.X.X.X (like 192.168.1.1)" 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 "" msgstr ""

View File

@@ -50,9 +50,6 @@ define Package/podkop/install
$(INSTALL_DIR) $(1)/etc/config $(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/etc/config/podkop $(1)/etc/config/podkop $(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_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_DATA) ./files/etc/hotplug.d/iface/50-podkop $(1)/etc/hotplug.d/iface/50-podkop $(INSTALL_DATA) ./files/etc/hotplug.d/iface/50-podkop $(1)/etc/hotplug.d/iface/50-podkop
endef endef

View File

@@ -1,19 +1,23 @@
config main 'main' config main 'main'
option mode '' option mode ''
option interface '' option interface ''
option proxy_string '' option proxy_config_type ''
#option outbound_json ''
#option proxy_string ''
option domain_list_enabled '1' option domain_list_enabled '1'
option domain_list 'ru_inside' option domain_list 'ru_inside'
option subnets_list_enabled '0' option subnets_list_enabled '0'
#list subnets 'twitter' #list subnets 'twitter'
option custom_domains_list_enabled '0' option custom_domains_list_type 'disable'
#list custom_domains '' #list custom_domains ''
#option custom_domains_text ''
option custom_local_domains_list_enabled '0' option custom_local_domains_list_enabled '0'
#list custom_local_domains '' #list custom_local_domains ''
option custom_download_domains_list_enabled '0' option custom_download_domains_list_enabled '0'
#list custom_download_domains '' #list custom_download_domains ''
option custom_subnets_list_enabled '0' option custom_domains_list_type 'disable'
#list custom_subnets '' #list custom_subnets ''
#custom_subnets_text ''
option custom_download_subnets_list_enabled '0' option custom_download_subnets_list_enabled '0'
#list custom_download_subnets '' #list custom_download_subnets ''
option all_traffic_from_ip_enabled '0' option all_traffic_from_ip_enabled '0'
@@ -26,15 +30,20 @@ config main 'main'
option socks5 '0' option socks5 '0'
option exclude_ntp '0' option exclude_ntp '0'
option update_interval '' option update_interval ''
option custom_domains_text
config second 'second' config second 'second'
option second_enable '0' option second_enable '0'
option second_mode 'proxy' option second_mode 'proxy'
option second_interface '' 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' option second_domain_service_enabled '0'
#list second_service_list 'youtube' #list second_service_list 'youtube'
option second_custom_domains_list_enabled '0' option second_custom_domains_type 'disable'
#list second_custom_domains 'ifconfig.io' #list second_custom_domains 'ifconfig.io'
option second_custom_subnets_list_enabled '0' #option second_custom_domains_text ''
#list second_custom_subnets '' 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_bool second_enable "second" "second_enable" "0"
config_get second_mode "second" "second_mode" "0" config_get second_mode "second" "second_mode" "0"
if [ "$second_enable" -eq "1" ] && [ "$second_mode" = "proxy" ]; then if [ "$second_enable" -eq "1" ] && [ "$second_mode" = "proxy" ]; then
config_get proxy_string "second" "second_proxy_string" config_get proxy_config_type "second" "second_proxy_config_type"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1603" if [ "$proxy_config_type" = "outbound" ]; then
elif [[ "$proxy_string" =~ ^vless:// ]]; then config_get outbound_json "second" "second_outbound_json"
sing_box_config_vless "$proxy_string" "1603" 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 else
log "Unsupported proxy type: $proxy_string" config_get proxy_string "second" "second_proxy_string"
return 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 fi
add_route_tproxy podkop2 add_route_tproxy podkop2
sing_box_config_check sing_box_config_check
@@ -78,28 +91,95 @@ start_service() {
outbound_main=$(mktemp) outbound_main=$(mktemp)
outbound_second=$(mktemp) outbound_second=$(mktemp)
config_get proxy_string main "proxy_string" # Main proxy config
if [[ "$proxy_string" =~ ^ss:// ]]; then config_get proxy_config_type main "proxy_config_type"
sing_box_config_outbound_shadowsocks "$proxy_string" "$outbound_main" main if [ "$proxy_config_type" = "outbound" ]; then
elif [[ "$proxy_string" =~ ^vless:// ]]; then config_get outbound_json main "outbound_json"
sing_box_config_outbound_vless "$proxy_string" "$outbound_main" main 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 else
log "Unsupported proxy type: $proxy_string" config_get proxy_string main "proxy_string"
return 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 fi
config_get proxy_string "second" "second_proxy_string" # Second proxy config
if [[ "$proxy_string" =~ ^ss:// ]]; then config_get proxy_config_type second "second_proxy_config_type"
sing_box_config_outbound_shadowsocks "$proxy_string" "$outbound_second" second if [ "$proxy_config_type" = "outbound" ]; then
elif [[ "$proxy_string" =~ ^vless:// ]]; then config_get outbound_json second "second_outbound_json"
sing_box_config_outbound_vless "$proxy_string" "$outbound_second" second 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 else
log "Unsupported proxy type: $proxy_string" config_get proxy_string "second" "second_proxy_string"
return 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 fi
jq --argjson outbounds "$(jq -s '{"outbounds": (.[0].outbounds + .[1].outbounds)}' "$outbound_main" "$outbound_second")" \ jq -s '{
'.outbounds += $outbounds.outbounds' /etc/podkop/sing-box-two-proxy-template.json >/etc/sing-box/config.json "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" rm -f "$outbound_main" "$outbound_second"
@@ -111,14 +191,27 @@ start_service() {
config_get_bool second_enable "second" "second_enable" "0" config_get_bool second_enable "second" "second_enable" "0"
config_get second_mode "second" "second_mode" "0" config_get second_mode "second" "second_mode" "0"
if [ "$second_enable" -eq "0" ] || [ "$second_mode" = "vpn" ]; then if [ "$second_enable" -eq "0" ] || [ "$second_mode" = "vpn" ]; then
config_get proxy_string main "proxy_string" config_get proxy_config_type main "proxy_config_type"
if [[ "$proxy_string" =~ ^ss:// ]]; then
sing_box_config_shadowsocks "$proxy_string" "1602" if [ "$proxy_config_type" = "outbound" ]; then
elif [[ "$proxy_string" =~ ^vless:// ]]; then config_get outbound_json main "outbound_json"
sing_box_config_vless "$proxy_string" "1602" 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 else
log "Unsupported proxy type: $proxy_string" config_get proxy_string main "proxy_string"
return 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 fi
add_route_tproxy podkop add_route_tproxy podkop
fi fi
@@ -274,6 +367,7 @@ remove_cron_job() {
} }
list_update() { list_update() {
# Main domains processing
config_get_bool domain_list_enabled "main" "domain_list_enabled" "0" config_get_bool domain_list_enabled "main" "domain_list_enabled" "0"
if [ "$domain_list_enabled" -eq 1 ]; then if [ "$domain_list_enabled" -eq 1 ]; then
log "Adding a common domains list" log "Adding a common domains list"
@@ -283,15 +377,24 @@ list_update() {
dnsmasq_config_check podkop-domains.lst dnsmasq_config_check podkop-domains.lst
fi fi
config_get_bool custom_domains_list_enabled "main" "custom_domains_list_enabled" "0" # Main custom domains processing
if [ "$custom_domains_list_enabled" -eq 1 ]; then 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" log "Adding a custom domains list"
add_set "podkop_domains" "main" add_set "podkop_domains" "main"
rm -f /tmp/dnsmasq.d/podkop-custom-domains.lst 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 dnsmasq_config_check podkop-custom-domains.lst
fi fi
# Main custom download domains
config_get_bool custom_download_domains_list_enabled "main" "custom_download_domains_list_enabled" "0" config_get_bool custom_download_domains_list_enabled "main" "custom_download_domains_list_enabled" "0"
if [ "$custom_download_domains_list_enabled" -eq 1 ]; then if [ "$custom_download_domains_list_enabled" -eq 1 ]; then
log "Adding a custom domains list from URL" 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" config_list_foreach main custom_download_domains "list_custom_download_domains_create" "podkop"
fi fi
# Main domains delist
config_get_bool custom_local_domains_list_enabled "main" "custom_local_domains_list_enabled" "0" config_get_bool custom_local_domains_list_enabled "main" "custom_local_domains_list_enabled" "0"
if [ "$custom_local_domains_list_enabled" -eq 1 ]; then if [ "$custom_local_domains_list_enabled" -eq 1 ]; then
log "Adding a custom local domain list" log "Adding a custom local domain list"
@@ -313,20 +417,56 @@ list_update() {
dnsmasq_config_check podkop-domains.lst dnsmasq_config_check podkop-domains.lst
fi fi
if [ "$domain_list_enabled" -eq 1 ] || [ "$custom_domains_list_enabled" -eq 1 ]; then # Main subnets processing
/etc/init.d/dnsmasq restart 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 fi
config_get_bool second_custom_domains_list_enabled "second" "second_custom_domains_list_enabled" "0" # Main custom subnets
if [ "$second_custom_domains_list_enabled" -eq 1 ]; then 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" log "Adding a custom domains list. Second podkop"
add_set "podkop2_domains" "second" add_set "podkop2_domains" "second"
rm -f /tmp/dnsmasq.d/podkop2-custom-domains.lst 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 dnsmasq_config_check podkop2-custom-domains.lst
fi fi
# Second service domains
config_get_bool second_domain_service_enabled "second" "second_domain_service_enabled" "0" config_get_bool second_domain_service_enabled "second" "second_domain_service_enabled" "0"
if [ "$second_domain_service_enabled" -eq 1 ]; then if [ "$second_domain_service_enabled" -eq 1 ]; then
log "Adding a service for podkop2" log "Adding a service for podkop2"
@@ -337,38 +477,26 @@ list_update() {
dnsmasq_config_check podkop2-domains.lst dnsmasq_config_check podkop2-domains.lst
fi fi
if [ "$second_custom_domains_list_enabled" -eq 1 ] || [ "$second_domain_service_enabled" -eq 1 ]; then # Second custom subnets
/etc/init.d/dnsmasq restart config_get second_custom_subnets_list_type "second" "second_custom_subnets_list_enabled" "disabled"
fi if [ "$second_custom_subnets_list_type" != "disabled" ]; then
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
log "Adding a custom subnets list. Second" log "Adding a custom subnets list. Second"
add_set "podkop2_subnets" "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 fi
} }
@@ -745,6 +873,34 @@ dnsmasq_config_check() {
fi 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() { sing_box_uci() {
local config="/etc/config/sing-box" local config="/etc/config/sing-box"
if grep -q "option enabled '0'" "$config" || if grep -q "option enabled '0'" "$config" ||
@@ -762,36 +918,61 @@ sing_box_config_shadowsocks() {
local STRING="$1" local STRING="$1"
local listen_port="$2" local listen_port="$2"
local encrypted_part=$(echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 --decode) # Определяем тип SS (2022 или old) по наличию : в base64 части
local method=$(echo "$encrypted_part" | cut -d':' -f1) if echo "$STRING" | cut -d'/' -f3 | cut -d'@' -f1 | base64 -d 2>/dev/null | grep -q ":"; then
local password=$(echo "$encrypted_part" | cut -d':' -f2-) # 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 server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1)
local port=$(echo "$STRING" | sed -n 's|.*:\([0-9]\+\).*|\1|p') 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" \ mv /tmp/ss_config.json /etc/sing-box/config.json
--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
} }
sing_box_config_vless() { sing_box_config_vless() {
@@ -799,167 +980,106 @@ sing_box_config_vless() {
local listen_port="$2" local listen_port="$2"
get_param() { 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) 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) 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 | awk -F'/' '{print $1}') 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") jq -n \
flow=$(get_param "flow") --arg listen_port "$listen_port" \
sni=$(get_param "sni") --arg server "$server" \
fp=$(get_param "fp") --argjson port "$port" \
security=$(get_param "security") --arg uuid "$uuid" \
pbk=$(get_param "pbk") --arg type "$(get_param "type")" \
sid=$(get_param "sid") --arg flow "$(get_param "flow")" \
encoding=$(get_param "packetEncoding") --arg sni "$(get_param "sni")" \
alpn=$(echo "$(get_param "alpn" | sed 's/%2C/,/g; s/%2F/\//g')" | jq -R -s -c 'split(",")' | sed 's/\\n//g') --arg fp "$(get_param "fp")" \
label=$(echo "$STRING" | cut -d'#' -f2) --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" \ if $type == "ws" then
--arg port "$port" \ .outbounds[0].transport = {
--arg uuid "$uuid" \ "type": "ws",
--arg type "$type" \ "path": $path
--arg flow "$flow" \ } |
--arg sni "$sni" \ if $host != "" then
--arg fp "$fp" \ .outbounds[0].transport.headers = {
--arg security "$security" \ "Host": $host
--arg pbk "$pbk" \ }
--arg sid "$sid" \ else . end
--argjson alpn "$alpn" \ elif $type == "grpc" then
--arg encoding "$encoding" \ .outbounds[0].transport = {
--arg listen_port "$listen_port" \ "type": "grpc"
'.inbounds[] |= }
if .type == "tproxy" then else . end |
.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
}
sing_box_config_outbound_shadowsocks() { if $security == "reality" or $security == "tls" then
local STRING="$1" .outbounds[0].tls = {
local outbound="$2" "enabled": true,
local name="$3" "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) if [ $? -eq 0 ]; then
local method=$(echo "$encrypted_part" | cut -d':' -f1) echo "Config created successfully"
local password=$(echo "$encrypted_part" | cut -d':' -f2-) else
echo "Error: Invalid JSON config generated"
local server=$(echo "$STRING" | cut -d'@' -f2 | cut -d':' -f1) return 1
local port=$(echo "$STRING" | cut -d':' -f3 | cut -d'#' -f1) fi
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
} }
sing_box_config_check() { sing_box_config_check() {
@@ -967,4 +1087,51 @@ sing_box_config_check() {
log "Sing-box configuration is invalid" log "Sing-box configuration is invalid"
return return
fi 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
}
}