From 10d74c6a6b481f9949efd4706a9b1fa448b6907f Mon Sep 17 00:00:00 2001 From: Ivan K Date: Sat, 30 Nov 2024 14:07:54 +0300 Subject: [PATCH] feat: Add proxy configuration options --- .../resources/view/podkop/podkop.js | 59 +++++++- podkop/files/etc/init.d/podkop | 142 ++++++++++++++---- 2 files changed, 170 insertions(+), 31 deletions(-) diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js index 5049292..1765eda 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js @@ -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'; @@ -315,10 +342,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'; diff --git a/podkop/files/etc/init.d/podkop b/podkop/files/etc/init.d/podkop index 42801cf..5aba541 100755 --- a/podkop/files/etc/init.d/podkop +++ b/podkop/files/etc/init.d/podkop @@ -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,27 +91,53 @@ 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 "$outbound_json" > "$outbound_main" + jq '.tag = "main"' "$outbound_main" > "${outbound_main}.tmp" && mv "${outbound_main}.tmp" "$outbound_main" + else + log "Missing main 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_outbound_shadowsocks "$proxy_string" "$outbound_main" main + elif [[ "$proxy_string" =~ ^vless:// ]]; then + sing_box_config_outbound_vless "$proxy_string" "$outbound_main" main + else + log "Unsupported proxy type or missing configuration for main" + 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 "$outbound_json" > "$outbound_second" + jq '.tag = "second"' "$outbound_second" > "${outbound_second}.tmp" && mv "${outbound_second}.tmp" "$outbound_second" + else + log "Missing second 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_outbound_shadowsocks "$proxy_string" "$outbound_second" second + elif [[ "$proxy_string" =~ ^vless:// ]]; then + sing_box_config_outbound_vless "$proxy_string" "$outbound_second" second + else + log "Unsupported proxy type or missing configuration for second" + return + fi fi - jq --argjson outbounds "$(jq -s '{"outbounds": (.[0].outbounds + .[1].outbounds)}' "$outbound_main" "$outbound_second")" \ + jq --argjson outbounds "$(jq -s '{"outbounds": [{"type":"selector","tag":"proxy","outbounds":["main","second"]}] + .[0].outbounds + .[1].outbounds}' "$outbound_main" "$outbound_second")" \ '.outbounds += $outbounds.outbounds' /etc/podkop/sing-box-two-proxy-template.json >/etc/sing-box/config.json rm -f "$outbound_main" "$outbound_second" @@ -111,14 +150,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 @@ -725,6 +777,38 @@ dnsmasq_config_check() { fi } +sing_box_config_outbound_json() { + local json_config="$1" + local listen_port="$2" + + # Create temporary file with base config structure + 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 + + # Add the outbound config using jq + jq --argjson outbound "$json_config" '.outbounds += [$outbound]' /tmp/base_config.json > /etc/sing-box/config.json + + # Cleanup + rm -f /tmp/base_config.json +} + sing_box_uci() { local config="/etc/config/sing-box" if grep -q "option enabled '0'" "$config" ||