diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..ee278a6 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,32 @@ +name: Test Build + +on: + push: + branches: + - main + +jobs: + build: + name: ${{ matrix.arch }} build + runs-on: ubuntu-latest + strategy: + matrix: + arch: + - x86_64 + - mips_24kc + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Build + uses: openwrt/gh-action-sdk@main + env: + ARCH: ${{ matrix.arch }} + + - name: Store packages + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.arch}}-packages + path: bin/packages/${{ matrix.arch }}/packages/*.ipk \ No newline at end of file diff --git a/luci-app-podkop/Makefile b/luci-app-podkop/Makefile new file mode 100644 index 0000000..1bfac6e --- /dev/null +++ b/luci-app-podkop/Makefile @@ -0,0 +1,19 @@ +# See /LICENSE for more information. +# This is free software, licensed under the GNU General Public License v2. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-podkop +PKG_VERSION:=1.0.1 +PKG_RELEASE:=1 + +LUCI_TITLE:=LuCI podkop app +LUCI_DEPENDS:=+luci-base +podkop +LUCI_PKGARCH:=all + +PKG_LICENSE:=GPL-2.0-or-later +PKG_MAINTAINER:=ITDog + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature \ No newline at end of file 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 new file mode 100644 index 0000000..1bebbc5 --- /dev/null +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js @@ -0,0 +1,97 @@ +'use strict'; +'require view'; +'require form'; +'require ui'; +'require network'; + +return view.extend({ + async render() { + var m, s, o; + + m = new form.Map('podkop', _('Podkop configuration')); + + s = m.section(form.TypedSection, 'podkop'); + s.anonymous = true; + + o = s.option(form.ListValue, 'mode', _('Mode'), _('Select VPN or Proxy')) + o.value('vpn', ('VPN')) + o.value('proxy', ('Proxy')) + + o = s.option(form.Value, 'proxy_string', _('Proxy String'), _('String vless:// or ss://')); + o.depends('mode', 'proxy'); + + // Get all interface + o = s.option(form.ListValue, 'interface', _('Interface'), _('Specify the interface')); + o.depends('mode', 'vpn'); + + try { + const devices = await network.getDevices(); + + const excludeInterfaces = ['br-lan', 'eth0', 'eth1']; + + devices.forEach(function (device) { + if (device.dev && device.dev.name) { + if (!excludeInterfaces.includes(device.dev.name)) { + o.value(device.dev.name, device.dev.name); + } + } else { + console.warn('Device name is undefined or empty'); + } + }); + } catch (error) { + console.error('Error fetching devices:', error); + } + + o = s.option(form.Flag, 'domain_list_enabled', _('Domain list enable'), _('github.com/itdoginfo/allow-domains')); + o.default = '0'; + o.rmempty = false; + + o = s.option(form.ListValue, 'domain_list', _('Domain list'), _('A select list')); + o.placeholder = 'placeholder'; + o.value('ru_inside', 'Russia inside'); + o.value('ru_outside', 'Russia outside'); + o.value('ua', 'Ukraine'); + o.depends('domain_list_enabled', '1'); + o.rmempty = false; + + o = s.option(form.Flag, 'delist_domains_enabled', _('Delist domains from main list enable')); + o.default = '0'; + o.rmempty = false; + + o = s.option(form.DynamicList, 'delist_domains', _('Delist domains'), _('Domains to be excluded')); + o.placeholder = 'Delist domains'; + o.depends('delist_domains_enabled', '1'); + o.rmempty = false; + + o = s.option(form.Flag, 'subnets_list_enabled', _('Subnets list enable')); + o.default = '0'; + o.rmempty = false; + + o = s.option(form.DynamicList, 'subnets', _('Subnets specify option')); + o.placeholder = 'Subnet list'; + o.value('twitter', 'Twitter(x.com)'); + o.value('meta', 'Meta'); + o.depends('subnets_list_enabled', '1'); + o.rmempty = false; + + o = s.option(form.Flag, 'custom_domains_list_enabled', _('Custom domains enable')); + o.default = '0'; + o.rmempty = false; + + o = s.option(form.DynamicList, 'custom_domains', _('Your domains')); + o.placeholder = 'Domains list'; + o.depends('custom_domains_list_enabled', '1'); + o.rmempty = false; + + o = s.option(form.Flag, 'custom_subnets_list_enabled', _('Custom subnets enable')); + o.default = '0'; + o.rmempty = false; + + o = s.option(form.DynamicList, 'custom_subnets', _('Your subnet')); + o.placeholder = 'Subnets list'; + o.depends('custom_subnets_list_enabled', '1'); + o.rmempty = false; + + return m.render(); + } +}); \ No newline at end of file diff --git a/luci-app-podkop/root/usr/share/luci/menu.d/luci-app-podkop.json b/luci-app-podkop/root/usr/share/luci/menu.d/luci-app-podkop.json new file mode 100644 index 0000000..e7e6ffa --- /dev/null +++ b/luci-app-podkop/root/usr/share/luci/menu.d/luci-app-podkop.json @@ -0,0 +1,14 @@ +{ + "admin/services/podkop": { + "title": "Podkop", + "order": 42, + "action": { + "type": "view", + "path": "podkop/podkop" + }, + "depends": { + "acl": [ "luci-app-podkop" ], + "uci": { "podkop": true } + } + } +} \ No newline at end of file diff --git a/luci-app-podkop/root/usr/share/rpcd/acl.d/luci-app-podkop.json b/luci-app-podkop/root/usr/share/rpcd/acl.d/luci-app-podkop.json new file mode 100644 index 0000000..f43d431 --- /dev/null +++ b/luci-app-podkop/root/usr/share/rpcd/acl.d/luci-app-podkop.json @@ -0,0 +1,21 @@ +{ + "luci-app-podkop": { + "description": "Grant UCI and RPC access to LuCI app podkop", + "read": { + "ubus": { + "luci.podkop": [ + "get_sample1", + "get_sample2" + ] + }, + "uci": [ + "podkop" + ] + }, + "write": { + "uci": [ + "podkop" + ] + } + } +} diff --git a/podkop/Makefile b/podkop/Makefile new file mode 100644 index 0000000..461a43d --- /dev/null +++ b/podkop/Makefile @@ -0,0 +1,71 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=podkop +PKG_VERSION:=1.0.3 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=ITDog +PKG_LICENSE:=GPL-2.0-or-later + +include $(INCLUDE_DIR)/package.mk + +define Package/podkop + SECTION:=net + CATEGORY:=Network + DEPENDS:=+curl +jq +kmod-nft-tproxy + TITLE:=Domain routing app + URL:=https://itdog.info + PKGARCH:=all +endef + +define Package/podkop/description + Domain routing. Use of VLESS, Shadowsocks technologies +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/podkop/postinst +#!/bin/sh + +if ! uci show ucitrack | grep -q 'podkop'; then + uci add ucitrack podkop + uci set ucitrack.@podkop[-1].init=podkop + uci commit ucitrack + + /etc/init.d/ucitrack restart +fi + +exit 0 +endef + +define Package/podkop/prerm +#!/bin/sh + +grep -q "105 podkop" /etc/iproute2/rt_tables && sed -i "/105 podkop/d" /etc/iproute2/rt_tables + +exit 0 +endef + +define Package/podkop/conffiles +/etc/config/podkop +endef + +define Package/podkop/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/etc/init.d/podkop $(1)/etc/init.d/podkop + + $(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 + +$(eval $(call BuildPackage,podkop)) diff --git a/podkop/files/etc/config/podkop b/podkop/files/etc/config/podkop new file mode 100644 index 0000000..b3acef3 --- /dev/null +++ b/podkop/files/etc/config/podkop @@ -0,0 +1,16 @@ +config podkop main + option mode 'proxy' + option interface 'wg0' + option proxy_string 'vless://60e7a3b2-5edb-4c0e-aa96-16702e4e0501@test.test:443/?type=tcp&encryption=none&flow=xtls-rprx-vision&sni=www.microsoft.com&fp=chrome&security=reality&pbk=O-IOLOcpVuzn9Eo3htHi0lxJ4YmeToNb6BhqUC7f7TQ&sid=4283c431d5a2263d#VLESS-podkop' + option domain_list_enabled '1' + option domain_list 'ru_inside' + option subnets_list_enabled '0' + list subnets 'twitter' + option custom_domains_list_enabled '0' + list custom_domains 'ifconfig.co' + option custom_subnets_list_enabled '0' + list custom_subnets '188.114.96.0/20' + option all_traffic_from_ip_enabled '0' + list all_traffic_ip '192.168.56.226' + option delist_domains_enabled '0' + list delist_domains 'zerossl.com' \ No newline at end of file diff --git a/podkop/files/etc/hotplug.d/iface/50-podkop b/podkop/files/etc/hotplug.d/iface/50-podkop new file mode 100755 index 0000000..6d2a74d --- /dev/null +++ b/podkop/files/etc/hotplug.d/iface/50-podkop @@ -0,0 +1,3 @@ +#!/bin/sh + +/etc/init.d/podkop add_route_interface diff --git a/podkop/files/etc/init.d/podkop b/podkop/files/etc/init.d/podkop new file mode 100755 index 0000000..bef5ff3 --- /dev/null +++ b/podkop/files/etc/init.d/podkop @@ -0,0 +1,476 @@ +#!/bin/sh /etc/rc.common + +START=99 + +script=$(readlink "$initscript") +NAME="$(basename ${script:-$initscript})" +config_load "$NAME" + +EXTRA_COMMANDS="list_update add_route_interface" +EXTRA_HELP=" list_update Updating domain and subnet lists + add_route_interface Adding route for interface" + +cron_job="0 4 * * * /etc/init.d/podkop list_update" + +start() { + log "Start podkop" + + dnsmasqfull + routing_table_create + add_mark + + config_get mode "main" "mode" + case "$mode" in + "vpn") + log "VPN mode" + log "You are using VPN mode, make sure you have installed all the necessary packages, configured, created the zone and forwarding." + config_get interface "main" "interface" "0" + if [ -n "$interface" ]; then + add_route_interface "$interface" + else + log "Interface undefined" + fi + ;; + "proxy") + log "Proxy mode" + config_get proxy_string main "proxy_string" + if ! command -v sing-box >/dev/null 2>&1; then + log "Sing-box isn't installed. Proxy mode works with sing-box" + exit 1 + fi + + if [[ "$proxy_string" =~ ^ss:// ]]; then + sing_box_config_shadowsocks "$proxy_string" + elif [[ "$proxy_string" =~ ^vless:// ]]; then + sing_box_config_vless "$proxy_string" + else + log "Unsupported proxy type: $proxy_string" + exit 1 + fi + + sing_box_config_check + sing_box_uci + /etc/init.d/sing-box restart + /etc/init.d/sing-box enable + add_route_tproxy + ;; + *) + log "Requires *vpn* or *proxy* value" + exit 1 + ;; + esac + + list_update + + if [ "$domain_list_enabled" -eq 1 ] || [ "$subnets_list_enabled" -eq 1 ]; then + add_cron_job + fi + + config_get_bool all_traffic_from_ip_enabled "main" "all_traffic_from_ip_enabled" "0" + if [ "$all_traffic_from_ip_enabled" -eq 1 ]; then + log "Adding an IP to redirect all traffic" + config_list_foreach main all_traffic_ip list_all_traffic_from_ip + fi +} + +stop() { + log "Stopping the podkop" + rm -f /tmp/dnsmasq.d/podkop* + remove_cron_job + + if nft list table inet PodkopTable >/dev/null 2>&1; then + nft delete table inet PodkopTable + fi + + if ip rule list | grep -q "podkop"; then + ip rule del fwmark 0x105 table podkop priority 105 + fi + + ip route flush table podkop + + if [ "$mode" = "proxy" ]; then + /etc/init.d/sing-box stop + /etc/init.d/sing-box disable + fi +} + +restart() { + stop + start +} + +reload() { + stop + start +} + +log() { + local message="$1" + local timestamp=$(date +"%Y-%m-%d %H:%M:%S") + local CYAN="\033[0;36m" + local GREEN="\033[0;32m" + local RESET="\033[0m" + + echo -e "${CYAN}[$timestamp]${RESET} ${GREEN}$message${RESET}" +} + +add_cron_job() { + if ! crontab -l | grep -q "podkop"; then + #echo "$cron_job" >>/etc/crontabs/root + crontab -l | { + cat + echo "$cron_job" + } | crontab - + log "The cron job has been created" + fi +} + +remove_cron_job() { + sed -i "\|podkop|d" /etc/crontabs/root + log "The cron job removed" +} + +list_update() { + config_get_bool domain_list_enabled "main" "domain_list_enabled" "0" + if [ "$domain_list_enabled" -eq 1 ]; then + log "Adding a common domains list" + add_set "podkop_domains" + config_get domain_list main "domain_list" + lists_domains_download "$domain_list" + 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 + log "Adding a custom domains list" + add_set "podkop_domains" + rm -f /tmp/dnsmasq.d/podkop-custom-domains.lst + config_list_foreach main custom_domains "list_custom_domains_create" + dnsmasq_config_check podkop-custom-domains.lst + fi + + config_get_bool delist_domains_enabled "main" "delist_domains_enabled" "0" + if [ "$delist_domains_enabled" -eq 1 ] && [ "$domain_list_enabled" -eq 1 ]; then + log "Exclude domains from the common list" + config_list_foreach main delist_domains "list_delist_domains" + 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 + 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" + config_list_foreach main subnets "list_subnets_download" + fi + + config_get_bool custom_subnets_list_enabled "main" "custom_subnets_list_enabled" "0" + if [ "$subnets_list_enabled" -eq 1 ]; then + log "Adding a custom subnets list" + add_set "podkop_subnets" + config_list_foreach main custom_subnets "list_custom_subnets_create" + fi +} + +dnsmasqfull() { + if /usr/sbin/dnsmasq -v | grep -q "no-nftset"; then + log "Dnsmasq-full is not installed. Future: link only" + log "Use script or:" + log "cd /tmp/ && /bin/opkg download dnsmasq-full && /bin/opkg remove dnsmasq && /bin/opkg install dnsmasq-full --cache /tmp/ && cp /etc/config/dhcp /etc/config/dhcp-old && mv /etc/config/dhcp-opkg /etc/config/dhcp" + exit 1 + fi +} + +routing_table_create() { + grep -q "105 podkop" /etc/iproute2/rt_tables || echo '105 podkop' >>/etc/iproute2/rt_tables +} + +add_set() { + local set_name="$1" + nft add table inet PodkopTable + log "Create set $set_name" + nft add chain inet PodkopTable mangle_podkop { type filter hook prerouting priority mangle \; policy accept \;} + nft add set inet PodkopTable "$set_name" { type ipv4_addr\; flags interval\; auto-merge\; } + config_get mode "main" "mode" + case "$mode" in + "vpn") + if nft list table inet PodkopTable | grep -q "chain prerouting"; then + nft delete chain inet PodkopTable prerouting + fi + + if ! nft list chain inet PodkopTable mangle_podkop | grep -q "ip daddr @"$set_name" meta mark set"; then + nft add rule inet PodkopTable mangle_podkop ip daddr @"$set_name" meta mark set 0x105 + fi + ;; + + "proxy") + nft add chain inet PodkopTable prerouting { type filter hook prerouting priority mangle \; } + if nft list table inet PodkopTable | grep -q "ip daddr @"$set_name" meta l4proto"; then + log "Nft rule tproxy exists" + else + log "Added nft rule tproxy" + nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto tcp meta mark set 0x105 tproxy ip to :1602 counter + nft add rule inet PodkopTable prerouting iifname "br-lan" ip daddr @"$set_name" meta l4proto udp meta mark set 0x105 tproxy ip to :1602 counter + fi + ;; + + *) + log "Requires *vpn* or *proxy* value" + exit 1 + ;; + esac +} + +add_route_interface() { + local interface="$1" + local retry_count=0 + local max_retries=20 + + if ! ip link show "$interface" >/dev/null 2>&1; then + log "Interface "$interface" does not exist, not possible to create a route" + exit 1 + fi + + if ip route show table podkop | grep -q "^default dev"; then + log "Route for "$interface" exists" + return 0 + fi + + log "Added route for "$interface"" + while [ $retry_count -lt $max_retries ]; do + if ip route add table podkop default dev "$interface" 2>&1 | grep -q "Network is down"; then + log "Error: Network is down. Let's try again in 3 seconds" + sleep 3 + retry_count=$((retry_count + 1)) + else + log "Route for "$interface" added" + return 0 + fi + done + + log "The maximum number of attempts has been exceeded. Failed to add a route." + exit 1 +} + +add_route_tproxy() { + if ! ip route list table podkop | grep -q "local default dev lo scope host"; then + log "Added route for tproxy" + ip route add local 0.0.0.0/0 dev lo table podkop + else + log "Route for tproxy exists" + fi +} + +add_mark() { + if ! ip rule list | grep -q "from all fwmark 0x105 lookup podkop"; then + log "Create marking rule" + ip -4 rule add fwmark 0x105 table podkop priority 105 + else + log "Marking rule exist" + fi +} + +lists_domains_download() { + local URL="$1" + + RU_INSIDE_DOMAINS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Russia/inside-dnsmasq-nfset.lst + RU_OUTSIDE_DOMAINS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Russia/outside-dnsmasq-nfset.lst + UA_DOMAINS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Ukraine/inside-dnsmasq-nfset.lst + + case "$URL" in + "ru_inside") + URL=$RU_INSIDE_DOMAINS + ;; + "ru_outside") + URL=$RU_OUTSIDE_DOMAINS + ;; + "ua") + URL=$UA_DOMAINS + ;; + *) + log "Unidentified list of domains" + exit 1 + ;; + esac + + count=0 + while true; do + if curl -m 3 github.com; then + curl -f $URL --output /tmp/dnsmasq.d/podkop-domains.lst + sed -i 's/fw4#vpn_domains/PodkopTable#podkop_domains/g' /tmp/dnsmasq.d/podkop-domains.lst + return 0 + else + log "GitHub is not available. Check the internet availability [$count sec]" + count=$((count + 1)) + fi + + if [ $count -lt 30 ]; then + sleep_interval=1 + elif [ $count -ge 30 ] && [ $count -lt 60 ]; then + sleep_interval=5 + elif [ $count -ge 60 ] && [ $count -lt 90 ]; then + sleep_interval=10 + else + sleep_interval=30 + fi + + sleep $sleep_interval + done +} + +list_subnets_download() { + TWITTER_SUBNETS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Subnets/IPv4/Twitter.lst + META_SUBNETS=https://raw.githubusercontent.com/itdoginfo/allow-domains/main/Subnets/IPv4/Meta.lst + local URL="$1" + + case "$URL" in + "twitter") + URL=$TWITTER_SUBNETS + ;; + "meta") + URL=$META_SUBNETS + ;; + *) + log "Unidentified list of subnets" + exit 1 + ;; + esac + + local filename=$(basename "$URL") + curl -f "$URL" --output "/tmp/podkop/$filename" + while IFS= read -r subnet; do + nft add element inet PodkopTable podkop_subnets { $subnet } + done <"/tmp/podkop/$filename" +} + +list_custom_domains_create() { + local domain="$1" + echo "nftset=/$domain/4#inet#PodkopTable#podkop_domains" >>/tmp/dnsmasq.d/podkop-custom-domains.lst + log "$domain added to the list" +} + +list_custom_subnets_create() { + local subnet="$1" + nft add element inet PodkopTable podkop_subnets { $subnet } +} + +list_all_traffic_from_ip() { + local ip="$1" + if ! nft list chain inet PodkopTable mangle_podkop | grep -q "ip saddr $ip"; then + nft add rule inet PodkopTable mangle_podkop ip saddr $ip meta mark set 0x105 + fi +} + +list_delist_domains() { + local domain="$1" + sed -i "/$domain/d" /tmp/dnsmasq.d/podkop-domains.lst + nft flush set inet PodkopTable podkop_domains + log "Strings containing '$domain' have been excluded from the list" +} + +dnsmasq_config_check() { + local config="$1" + if ! /usr/sbin/dnsmasq --conf-file=/tmp/dnsmasq.d/$config --test 2>&1 | grep -q "syntax check OK"; then + log "Dnsmasq config $config contains errors. Break" + exit 1 + fi +} + +sing_box_uci() { + local config="/etc/config/sing-box" + if grep -q "option enabled '0'" "$config" || + grep -q "option user 'sing-box'" "$config"; then + sed -i \ + -e "s/option enabled '0'/option enabled '1'/" \ + -e "s/option user 'sing-box'/option user 'root'/" $config + log "Change sing-box UCI config" + else + log "Sing-box UCI config OK" + fi +} + +sing_box_config_shadowsocks() { + local STRING="$1" + + 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-template.json" + + jq --arg server "$server" \ + --arg port "$port" \ + --arg method "$method" \ + --arg password "$password" \ + '.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() { + local STRING="$1" + + 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) + 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") + label=$(echo "$STRING" | cut -d'#' -f2) + + template_config="/etc/podkop/sing-box-vless-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" \ + '.outbounds[] |= + if .type == "vless" then + .server = $server | + .server_port = ($port | tonumber) | + .uuid = $uuid | + if $flow == "" then del(.flow) else .flow = $flow end | + .tls.server_name = $sni | + .tls.utls.fingerprint = $fp | + .tls.reality.public_key = $pbk | + .tls.reality.short_id = $sid + else + . + end' "$template_config" >/etc/sing-box/config.json + #! Добавить label в luci +} + +sing_box_config_check() { + if ! sing-box -c /etc/sing-box/config.json check >/dev/null 2>&1; then + log "Sing-box configuration is invalid" + exit 1 + fi +} diff --git a/podkop/files/etc/podkop/sing-box-shadowsocks-template.json b/podkop/files/etc/podkop/sing-box-shadowsocks-template.json new file mode 100644 index 0000000..6d4e6eb --- /dev/null +++ b/podkop/files/etc/podkop/sing-box-shadowsocks-template.json @@ -0,0 +1,25 @@ +{ + "log": { + "level": "warn" + }, + "inbounds": [ + { + "type": "tproxy", + "listen": "::", + "listen_port": 1602, + "sniff": false + } + ], + "outbounds": [ + { + "type": "shadowsocks", + "server": "$HOST", + "server_port": "$PORT", + "method": "$METHOD", + "password": "$PASS" + } + ], + "route": { + "auto_detect_interface": true + } +} \ No newline at end of file diff --git a/podkop/files/etc/podkop/sing-box-vless-template.json b/podkop/files/etc/podkop/sing-box-vless-template.json new file mode 100644 index 0000000..cb945ed --- /dev/null +++ b/podkop/files/etc/podkop/sing-box-vless-template.json @@ -0,0 +1,39 @@ +{ + "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 + } +} \ No newline at end of file