2026-02-14 19:52:31 +04:00
#!/bin/sh
. /lib/functions.sh
2026-04-11 18:05:21 +04:00
readonly LNET_RESERVED = "127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 169.254.0.0/16 100.64.0.0/10 224.0.0.0/4 255.255.255.255/32 0.0.0.0/8"
readonly LNET_NAME = "system_lnet"
2026-04-12 19:35:40 +04:00
readonly TEST_DOMAIN = "github.com"
readonly PING_ADDR = 1.1.1.1
readonly RT_TABLE = 110
readonly DEBUG = 0
readonly DEBUG_LOG = "/tmp/xray-manager.log"
2026-04-11 18:05:21 +04:00
2026-02-14 19:52:31 +04:00
_log() {
2026-04-12 19:35:40 +04:00
local msg = " $1 "
local level = " ${ 2 :- info } "
local to_console = " ${ 3 :- 1 } "
[ " $level " = "debug" ] && [ " $DEBUG " -ne 1 ] && return
if [ " $DEBUG " = "1" ] && [ -n " $DEBUG_LOG " ] ; then
2026-04-13 13:50:57 +04:00
echo " $( date '+%Y-%m-%d %H:%M:%S' ) $msg " >> " $DEBUG_LOG "
2026-04-11 18:05:21 +04:00
fi
2026-02-14 19:52:31 +04:00
2026-04-13 13:50:57 +04:00
local sys_level = "info"
2026-04-12 19:35:40 +04:00
case " $level " in
2026-04-13 13:50:57 +04:00
info) sys_level = "info" ;;
crit) sys_level = "crit" ;;
err) sys_level = "err" ;;
warn) sys_level = "warning" ;;
debug) sys_level = "debug" ;;
2026-04-12 19:35:40 +04:00
esac
2026-04-13 13:50:57 +04:00
[ " $level " != "debug" ] && logger -t xray-manager -p "daemon. $sys_level " " $msg "
if [ " $to_console " = "1" ] ; then
printf "%s\n" " $msg "
fi
2026-04-11 18:05:21 +04:00
}
2026-02-14 19:52:31 +04:00
2026-04-12 19:35:40 +04:00
_get_md5() { echo " $1 " | md5sum | cut -d' ' -f1; }
2026-02-21 23:04:38 +04:00
_init_vars() {
2026-04-13 13:50:57 +04:00
_log "config: loading configuration" "debug"
2026-02-21 23:04:38 +04:00
config_load xray-manager
2026-04-11 18:05:21 +04:00
local s = "main"
2026-02-21 23:04:38 +04:00
TABLE = $( uci -q get xray-manager.$s .table_name)
TPROXY_PORT = $( uci -q get xray-manager.$s .tproxy_port)
TPROXY_MARK = $( uci -q get xray-manager.$s .tproxy_mark)
CLIENT_MARK = $( uci -q get xray-manager.$s .client_mark)
2026-02-22 09:12:22 +04:00
TIMEOUT = $( uci -q get xray-manager.$s .timeout)
2026-02-21 23:04:38 +04:00
IPNET_DIR = $( uci -q get xray-manager.$s .ipnet_dir)
DNSMASQ_DIR = $( uci -q get xray-manager.$s .dnsmasq_dir)
CACHE_DIR = $( uci -q get xray-manager.$s .cache_dir)
ACTIVE_LIST = $( uci -q get xray-manager.$s .active_list)
2026-04-11 18:05:21 +04:00
_get_proxy_list() { PROXY_SERVERS = " ${ PROXY_SERVERS }${ PROXY_SERVERS :+ } $1 " ; }
PROXY_SERVERS = ""
config_list_foreach " $s " proxy_ip _get_proxy_list
2026-02-21 23:04:38 +04:00
2026-04-11 18:05:21 +04:00
local required_vars = "TABLE TPROXY_PORT TPROXY_MARK CLIENT_MARK TIMEOUT IPNET_DIR DNSMASQ_DIR CACHE_DIR ACTIVE_LIST"
2026-02-21 23:04:38 +04:00
for var in $required_vars ; do
eval val = \$ $var
if [ -z " $val " ] ; then
2026-04-13 13:50:57 +04:00
_log "config: variable ' $var ' is missing" "crit"
2026-02-21 23:04:38 +04:00
return 1
fi
done
2026-04-13 13:50:57 +04:00
_log "config: loaded table= $TABLE , port= $TPROXY_PORT , mark= $TPROXY_MARK " "debug"
2026-02-21 23:04:38 +04:00
mkdir -p " $IPNET_DIR " " $DNSMASQ_DIR " " $CACHE_DIR " " ${ ACTIVE_LIST %/* } "
2026-04-12 19:35:40 +04:00
if [ " $DEBUG " = "1" ] && [ -n " $DEBUG_LOG " ] ; then
: > " $DEBUG_LOG " 2>/dev/null
2026-02-21 23:04:38 +04:00
fi
return 0
}
2026-04-12 20:00:19 +04:00
_validate_config() {
2026-04-13 13:50:57 +04:00
_log "config: validating uci syntax" "debug"
2026-04-12 20:00:19 +04:00
local dns_confdir
dns_confdir = $( uci -q get dhcp.@dnsmasq[ 0] .confdir)
if [ -z " $dns_confdir " ] || ! echo " $dns_confdir " | grep -q " $DNSMASQ_DIR " ; then
2026-04-13 13:50:57 +04:00
_log "config: $DNSMASQ_DIR is not set in dnsmasq" "warn"
2026-04-12 20:00:19 +04:00
fi
local allowed_opts = "name direction exclude parent ip domain url_ip url_domain"
validate_list_section() {
local s = " $1 " name direction
config_get name " $s " name
config_get direction " $s " direction "dst"
if [ -z " $name " ] ; then
2026-04-13 13:50:57 +04:00
_log "config: section $s is missing name" "crit"
2026-04-12 20:00:19 +04:00
exit 1
fi
local current_opt
for current_opt in $( uci show xray-manager." $s " | cut -d'.' -f3 | cut -d'=' -f1 | sort -u) ; do
case " $current_opt " in
.*) continue ;;
esac
if ! echo " $allowed_opts " | grep -qw " $current_opt " ; then
2026-04-13 13:50:57 +04:00
_log " $name : unknown option: ' $current_opt '" "err"
2026-04-12 20:00:19 +04:00
exit 1
fi
done
case " $direction " in
src| dst| out| force_src) ;;
2026-04-13 13:50:57 +04:00
*) _log " $name : invalid direction: $direction " "err" ; exit 1 ;;
2026-04-12 20:00:19 +04:00
esac
}
config_foreach validate_list_section "xray-list"
2026-04-13 13:50:57 +04:00
_log "config: validation complete" "info"
2026-04-12 20:00:19 +04:00
}
2026-02-14 19:52:31 +04:00
_nft_init() {
2026-04-13 13:50:57 +04:00
_log " $TABLE : initializing nft table" "info"
2026-02-14 19:52:31 +04:00
nft add table ip " $TABLE " 2>/dev/null
2026-04-12 19:35:40 +04:00
2026-04-13 13:50:57 +04:00
_log " $TABLE : setting up base chains" "debug"
2026-02-14 19:52:31 +04:00
nft add chain ip " $TABLE " prerouting { type filter hook prerouting priority mangle \; policy accept \; } 2>/dev/null
nft flush chain ip " $TABLE " prerouting
2026-02-18 01:36:35 +04:00
nft add rule ip " $TABLE " prerouting fib daddr type local accept
2026-04-12 19:35:40 +04:00
2026-04-11 18:05:21 +04:00
nft add chain ip " $TABLE " output { type route hook output priority -150 \; policy accept \; } 2>/dev/null
nft flush chain ip " $TABLE " output
nft add rule ip " $TABLE " output fib daddr type local accept
2026-04-13 13:50:57 +04:00
local mark_hex = $( printf '0x%x' " $TPROXY_MARK " )
_log "route: configuring table $RT_TABLE , mark $mark_hex " "debug"
2026-04-12 19:35:40 +04:00
ip route show table $RT_TABLE | grep -q "local default" || ip route add local default dev lo table $RT_TABLE
ip rule show | grep -q "fwmark $mark_hex lookup $RT_TABLE " || ip rule add fwmark " $TPROXY_MARK " table $RT_TABLE
2026-02-21 23:04:38 +04:00
}
2026-04-12 19:35:40 +04:00
_nft_prepare_data() {
local id = " $1 " file = " $2 " type = " $3 " changed = " $4 " dir = " $5 "
local sname = "s_ $id "
local set_params = "type ipv4_addr; flags interval; auto-merge;"
2026-02-14 19:52:31 +04:00
2026-04-12 19:35:40 +04:00
[[ " $type " == *dom ]] && set_params = "type ipv4_addr; flags interval,timeout; timeout $TIMEOUT ; auto-merge;"
2026-02-22 09:12:22 +04:00
2026-04-13 13:50:57 +04:00
_log " $sname : creating nft set" "debug"
2026-04-12 19:35:40 +04:00
nft add set ip " $TABLE " " $sname " { $set_params } 2>/dev/null
if [ -s " $file " ] && [[ " $type " == *"ip" * ]] ; then
if [ " $changed " = "1" ] || [ " $FULL_LOAD " = "1" ] ; then
2026-04-13 13:50:57 +04:00
_log " $sname : flushing and loading elements" "debug"
2026-04-12 19:35:40 +04:00
nft flush set ip " $TABLE " " $sname "
{
printf "add element ip %s %s { " " $TABLE " " $sname "
awk '/^[[:space:]]*#/ || /^[[:space:]]*$/ { next } { addr = ($1 ~ /\// ? $1 : $1"/32"); printf "%s%s", (count++ ? ", " : ""), addr }' " $file "
printf " }\n"
} | nft -f -
2026-04-11 18:05:21 +04:00
fi
fi
2026-02-21 23:04:38 +04:00
2026-04-12 19:35:40 +04:00
if [ " $dir " = "force_src" ] ; then
local cn = "f_ $id "
2026-04-13 13:50:57 +04:00
_log " $cn : creating force-chain" "debug"
2026-04-12 19:35:40 +04:00
nft add chain ip " $TABLE " " $cn " 2>/dev/null
nft flush chain ip " $TABLE " " $cn "
nft add rule ip " $TABLE " " $cn " meta l4proto "{ tcp, udp }" tproxy to 127.0.0.1:" $TPROXY_PORT " ct mark set " $CLIENT_MARK " meta mark set " $TPROXY_MARK " accept 2>/dev/null
2026-04-11 18:05:21 +04:00
fi
2026-04-12 19:35:40 +04:00
}
2026-04-11 18:05:21 +04:00
2026-04-12 19:35:40 +04:00
_nft_apply_rule() {
local sname = " $1 " dir = " $2 " exc = " $3 " parent = " $4 " mode = " $5 "
local nft_sname = "s_ $sname "
local sel = "ip daddr"
[ " $dir " = "src" ] && sel = "ip saddr"
case " $mode " in
jumps)
[ " $dir " = "force_src" ] && {
2026-04-13 13:50:57 +04:00
_log " $nft_sname : applying jump to f_ $sname " "debug"
2026-04-12 19:35:40 +04:00
nft add rule ip " $TABLE " prerouting ip saddr "@ $nft_sname " jump "f_ ${ sname } " 2>/dev/null
}
;;
exclude)
[ " $exc " != "1" ] && [ " $sname " != " $LNET_NAME " ] && return
local target_info = ""
[ -n " $parent " ] && target_info = " target= $parent "
2026-04-13 13:50:57 +04:00
_log " $nft_sname : applying exclude rule $target_info " "debug"
2026-04-12 19:35:40 +04:00
if [ -n " $parent " ] ; then
nft insert rule ip " $TABLE " " $parent " ip daddr "@ $nft_sname " accept 2>/dev/null
else
[ " $dir " != "out" ] && nft add rule ip " $TABLE " prerouting " $sel " "@ $nft_sname " accept 2>/dev/null
[ " $dir " = "out" ] && nft add rule ip " $TABLE " output " $sel " "@ $nft_sname " accept 2>/dev/null
fi
;;
main_rules)
[ " $exc " = "1" ] || [ " $dir " = "force_src" ] && return
2026-04-13 13:50:57 +04:00
_log " $nft_sname : applying tproxy rules" "debug"
2026-04-12 19:35:40 +04:00
if [ " $mode_chain " = "prerouting" ] && [ " $dir " != "out" ] ; then
if [ " $dir " = "src" ] ; then
nft add rule ip " $TABLE " prerouting ip saddr "@ $nft_sname " ct mark set " $CLIENT_MARK " 2>/dev/null
else
nft add rule ip " $TABLE " prerouting ct mark " $CLIENT_MARK " ip daddr "@ $nft_sname " meta l4proto "{ tcp, udp }" tproxy to 127.0.0.1:" $TPROXY_PORT " meta mark set " $TPROXY_MARK " accept 2>/dev/null
fi
elif [ " $mode_chain " = "output" ] && [ " $dir " = "out" ] ; then
nft add rule ip " $TABLE " output ip daddr "@ $nft_sname " meta l4proto "{ tcp, udp }" counter ct mark set " $CLIENT_MARK " meta mark set " $TPROXY_MARK " accept 2>/dev/null
fi
;;
esac
2026-02-14 19:52:31 +04:00
}
_process_item() {
2026-04-12 19:35:40 +04:00
local id = " $1 " val = " $2 " type = " $3 " dir = " $4 " exc = " $5 " parent = " $6 "
local fullpath hfile changed = 0
2026-02-14 19:52:31 +04:00
2026-04-12 19:35:40 +04:00
[[ " $type " == *dom ]] && fullpath = " $DNSMASQ_DIR / $id .lst" || fullpath = " $IPNET_DIR / $id .lst"
2026-02-14 19:52:31 +04:00
hfile = " $CACHE_DIR / $id .hash"
echo " $fullpath " >> " $ACTIVE_LIST "
echo " $hfile " >> " $ACTIVE_LIST "
2026-04-12 19:35:40 +04:00
2026-02-14 19:52:31 +04:00
local new_hash = $( _get_md5 " $val " )
local old_hash = $( cat " $hfile " 2>/dev/null)
2026-04-12 19:35:40 +04:00
local status = "stable"
2026-04-13 13:50:57 +04:00
if [ " $new_hash " != " $old_hash " ] ; then
status = "changed"
[ " $SKIP_URL " = "1" ] && [[ " $type " == u* ]] && NEED_UPDATE = 1
fi
_log " $id status: $status " "debug"
2026-04-11 18:05:21 +04:00
2026-04-12 19:35:40 +04:00
if [ " $SKIP_URL " = "1" ] && [[ " $type " == u* ]] ; then
2026-04-13 13:50:57 +04:00
_log " $id : skipping download (reload mode)" "debug"
[ ! -f " $fullpath " ] && { _log " $id : data file missing" "warn" ; NEED_UPDATE = 1; }
2026-04-12 19:35:40 +04:00
[ -f " $fullpath " ] && _nft_prepare_data " $id " " $fullpath " " $type " 0 " $dir "
2026-02-21 23:04:38 +04:00
return
2026-02-14 19:52:31 +04:00
fi
2026-03-23 10:46:21 +04:00
if [ " $new_hash " != " $old_hash " ] || [ ! -f " $fullpath " ] || [ " $SKIP_URL " = "0" ] ; then
2026-02-14 19:52:31 +04:00
case " $type " in
2026-04-12 19:35:40 +04:00
ip)
echo " $val " | tr ' ' '\n' | sed -e 's/\r//g' -e '/^#/d' -e '/^[[:space:]]*$/d' -e '/\//! s|$|/32|' | sort -u > " $fullpath .tmp"
2026-03-23 10:46:21 +04:00
;;
2026-02-14 19:52:31 +04:00
dom)
2026-04-12 19:35:40 +04:00
echo " $val " | tr ' ' '\n' | awk -v t = " $TABLE " -v i = "s_ $id " '/^[[:space:]]*#/ || /^[[:space:]]*$/ { next } { gsub(/\r/, ""); printf "nftset=/%s/4#ip#%s#%s\n", tolower($1), t, i }' | sort -u > " $fullpath .tmp"
2026-03-23 10:46:21 +04:00
;;
2026-02-14 19:52:31 +04:00
uip| udom)
2026-04-13 13:50:57 +04:00
_log " $id : fetching remote list" "info"
2026-04-12 19:35:40 +04:00
local tmp_all = " $CACHE_DIR /dl_ $id "
2026-04-05 14:24:00 +04:00
: > " $tmp_all "
2026-02-21 23:04:38 +04:00
local dl_ok = 0
2026-04-12 19:35:40 +04:00
2026-02-14 19:52:31 +04:00
for url in $val ; do
2026-04-12 19:35:40 +04:00
local uhash = $( echo " $url " | md5sum | cut -c1-8)
2026-04-13 13:50:57 +04:00
_log " $id : downloading $url " "debug"
2026-04-12 19:35:40 +04:00
local cache_raw = " $CACHE_DIR / ${ id } _ $uhash .raw"
local hfile_tmp = " $CACHE_DIR /h_ $id "
local etag_f = " $CACHE_DIR / ${ id } _ $uhash .etag"
local etag = $( cat " $etag_f " 2>/dev/null)
curl -sSfL --connect-timeout 15 ${ etag :+-H "If-None-Match: \" $etag \"" } -D " $hfile_tmp " " $url " > " $tmp_all .raw"
local res = $?
2026-03-23 10:46:21 +04:00
2026-04-12 19:35:40 +04:00
if grep -q "304" " $hfile_tmp " 2>/dev/null; then
2026-04-13 13:50:57 +04:00
_log " $id : 304 not modified" "info"
2026-04-12 19:35:40 +04:00
[ -f " $cache_raw " ] && cat " $cache_raw " >> " $tmp_all " && dl_ok = 1
elif [ $res -eq 0 ] && [ -s " $tmp_all .raw" ] ; then
2026-04-13 13:50:57 +04:00
_log " $id : 200 ok" "info"
2026-04-12 19:35:40 +04:00
grep -i "^etag:" " $hfile_tmp " | awk -F': ' '{print $2}' | sed 's/W\///; s/["\r\n ]//g' > " $etag_f "
cat " $tmp_all .raw" > " $cache_raw "
cat " $tmp_all .raw" >> " $tmp_all "
2026-03-23 10:46:21 +04:00
dl_ok = 1
else
2026-04-13 13:50:57 +04:00
_log " $id : download failed, using local cache" "warn"
2026-04-12 19:35:40 +04:00
[ -f " $cache_raw " ] && cat " $cache_raw " >> " $tmp_all " && dl_ok = 1
2026-03-23 10:46:21 +04:00
fi
2026-02-14 19:52:31 +04:00
done
2026-03-23 10:46:21 +04:00
2026-04-12 19:35:40 +04:00
if [ " $dl_ok " = "1" ] ; then
2026-02-21 23:04:38 +04:00
if [ " $type " = "uip" ] ; then
2026-04-12 19:35:40 +04:00
sed -e 's/\r//g' -e '/^#/d' -e '/^[[:space:]]*$/d' " $tmp_all " | awk '{ print ($1 ~ /\// ? $1 : $1"/32") }' | sort -u > " $fullpath .tmp"
2026-02-21 23:04:38 +04:00
else
2026-04-12 19:35:40 +04:00
tr 'A-Z' 'a-z' < " $tmp_all " | grep -oE '([a-z0-9-]+\.)+[a-z]{2,}' | sort -u | awk -v t = " $TABLE " -v i = "s_ $id " '{ printf "nftset=/%s/4#ip#%s#%s\n", $1, t, i }' > " $fullpath .tmp"
2026-02-21 23:04:38 +04:00
fi
2026-04-12 19:35:40 +04:00
fi
;;
2026-02-14 19:52:31 +04:00
esac
2026-04-12 19:35:40 +04:00
if [ -s " $fullpath .tmp" ] && ! cmp -s " $fullpath .tmp" " $fullpath " ; then
mv " $fullpath .tmp" " $fullpath "
changed = 1
[[ " $type " == *dom ]] && DNS_CHANGES = 1
2026-04-13 13:50:57 +04:00
_log " $id : list updated" "info"
2026-04-12 19:35:40 +04:00
else
rm -f " $fullpath .tmp"
fi
2026-02-14 19:52:31 +04:00
echo " $new_hash " > " $hfile "
fi
2026-04-12 19:35:40 +04:00
_nft_prepare_data " $id " " $fullpath " " $type " " $changed " " $dir "
2026-02-14 19:52:31 +04:00
}
_process_section() {
2026-04-12 19:35:40 +04:00
local s = " $1 " mode = " $2 " name dir exc parent
config_get name " $s " name
config_get dir " $s " direction "dst"
config_get exc " $s " exclude "0"
2026-04-11 18:05:21 +04:00
config_get parent " $s " parent
2026-04-12 19:35:40 +04:00
2026-02-14 19:52:31 +04:00
[ -z " $name " ] && return
2026-02-21 23:04:38 +04:00
name = ${ name //[^a-zA-Z0-9_]/ }
2026-02-14 19:52:31 +04:00
2026-04-12 19:35:40 +04:00
[ " $exc " = "1" ] && [ -n " $parent " ] && parent = "f_ ${ parent } _ip"
2026-02-14 19:52:31 +04:00
2026-04-12 19:35:40 +04:00
if [ -z " $mode " ] ; then
2026-04-13 13:50:57 +04:00
_log " $name : configuring section" "debug"
2026-04-12 19:35:40 +04:00
_get_v() { V = " ${ V }${ V :+ } $1 " ; }
V = "" ; config_list_foreach " $s " ip _get_v; [ -n " $V " ] && _process_item " ${ name } _ip" " $V " "ip" " $dir " " $exc " " $parent "
V = "" ; config_list_foreach " $s " domain _get_v; [ -n " $V " ] && _process_item " ${ name } _dom" " $V " "dom" " $dir " " $exc " " $parent "
V = "" ; config_list_foreach " $s " url_ip _get_v; [ -n " $V " ] && _process_item " ${ name } _uip" " $V " "uip" " $dir " " $exc " " $parent "
V = "" ; config_list_foreach " $s " url_domain _get_v; [ -n " $V " ] && _process_item " ${ name } _udom" " $V " "udom" " $dir " " $exc " " $parent "
else
[ -f " $IPNET_DIR / ${ name } _ip.lst" ] && _nft_apply_rule " ${ name } _ip" " $dir " " $exc " " $parent " " $mode "
[ -f " $DNSMASQ_DIR / ${ name } _dom.lst" ] && _nft_apply_rule " ${ name } _dom" " $dir " " $exc " " $parent " " $mode "
[ -f " $IPNET_DIR / ${ name } _uip.lst" ] && _nft_apply_rule " ${ name } _uip" " $dir " " $exc " " $parent " " $mode "
[ -f " $DNSMASQ_DIR / ${ name } _udom.lst" ] && _nft_apply_rule " ${ name } _udom" " $dir " " $exc " " $parent " " $mode "
if [ " $mode " = "exclude" ] && [ " $dir " = "force_src" ] ; then
2026-04-13 13:50:57 +04:00
_log " $name : force-src: injecting lnet exclusion" "debug"
2026-04-12 19:35:40 +04:00
_nft_apply_rule " $LNET_NAME " "dst" "1" "f_ ${ name } _ip" "exclude"
2026-04-11 18:05:21 +04:00
fi
fi
}
2026-02-21 23:04:38 +04:00
_run() {
2026-04-13 13:50:57 +04:00
_log "main: starting execution ( $1 )" "info"
2026-04-11 18:05:21 +04:00
_init_vars || return 1
2026-04-12 20:00:19 +04:00
_validate_config
2026-04-12 19:35:40 +04:00
DNS_CHANGES = 0; NEED_UPDATE = 0; : > " $ACTIVE_LIST "
2026-04-11 18:05:21 +04:00
2026-04-12 19:35:40 +04:00
[ " $FULL_LOAD " = "1" ] && _wait_for_net
2026-04-13 13:50:57 +04:00
_wait_for_net
2026-04-12 19:35:40 +04:00
_nft_init
2026-04-11 18:05:21 +04:00
2026-04-13 13:50:57 +04:00
_log "main: processing data sections" "debug"
2026-02-14 19:52:31 +04:00
config_foreach _process_section "xray-list"
2026-04-11 18:05:21 +04:00
_process_item " $LNET_NAME " " $LNET_RESERVED " "ip" "dst" "1"
2026-04-13 13:50:57 +04:00
_log "main: applying nft rules" "info"
2026-04-12 19:35:40 +04:00
config_foreach _process_section "xray-list" "jumps"
_nft_apply_rule " $LNET_NAME " "dst" "1" "" "exclude"
config_foreach _process_section "xray-list" "exclude"
2026-04-11 18:05:21 +04:00
2026-04-13 13:50:57 +04:00
_log "main: applying proxy bypass" "debug"
2026-04-12 19:35:40 +04:00
[ -n " $PROXY_SERVERS " ] && nft add rule ip " $TABLE " output ip daddr "@s_proxy_servers" accept 2>/dev/null
2026-04-11 18:05:21 +04:00
2026-04-13 13:50:57 +04:00
_log "main: applying tproxy rules" "debug"
2026-04-12 19:35:40 +04:00
mode_chain = "prerouting" ; config_foreach _process_section "xray-list" "main_rules"
mode_chain = "output" ; config_foreach _process_section "xray-list" "main_rules"
2026-04-13 13:50:57 +04:00
_log "main: cleaning up orphans" "info"
2026-04-12 19:35:40 +04:00
if [ -n " $IPNET_DIR " ] && [ -n " $DNSMASQ_DIR " ] ; then
for f in " $IPNET_DIR " /* " $DNSMASQ_DIR " /*; do
[ -e " $f " ] || continue
if ! grep -Fxq " $f " " $ACTIVE_LIST " ; then
local fname = " ${ f ##*/ } "
2026-04-13 13:50:57 +04:00
_log "orphan: removing $fname " "info"
2026-04-12 19:35:40 +04:00
case " $f " in " $DNSMASQ_DIR " /*) DNS_CHANGES = 1 ;; esac
nft delete set ip " $TABLE " "s_ ${ fname %.* } " 2>/dev/null
rm -f " $f "
fi
done
2026-03-23 10:46:21 +04:00
fi
2026-04-12 19:35:40 +04:00
2026-04-13 13:50:57 +04:00
[ " $DNS_CHANGES " = "1" ] && { _log "dnsmasq: restarting service" "info" ; /etc/init.d/dnsmasq restart; }
[ " $SKIP_URL " = "1" ] && [ " $NEED_UPDATE " = "1" ] && {
_log "main: outdated lists detected" "warn"
_log "main: run 'update' to refresh data" "warn"
}
2026-04-12 19:35:40 +04:00
2026-04-13 13:50:57 +04:00
_log "main: execution finished" "info"
2026-04-12 19:35:40 +04:00
}
_wait_for_net() {
2026-04-13 13:50:57 +04:00
_log "network: checking connectivity" "info"
2026-04-12 19:35:40 +04:00
local t = 1
while [ " $t " -le 20 ] ; do
2026-04-13 13:50:57 +04:00
if ping -q -c 1 -W 2 " $PING_ADDR " >/dev/null 2>& 1; then
if nslookup " $TEST_DOMAIN " >/dev/null 2>& 1; then
_log "network: access confirmed" "info"
return 0
else
_log "network: dns resolution failed" "warn"
fi
else
_log "network: unreachable" "warn"
2026-04-12 19:35:40 +04:00
fi
sleep 2; t = $(( t + 2 ))
done
2026-04-13 13:50:57 +04:00
_log "network: timeout: switching to offline mode" "warn"
2026-04-12 19:35:40 +04:00
export SKIP_URL = 1
2026-02-14 19:52:31 +04:00
}
_stop() {
2026-04-13 13:50:57 +04:00
_log "main: stopping service" "info"
2026-04-12 19:35:40 +04:00
_init_vars
2026-02-14 19:52:31 +04:00
nft delete table ip " $TABLE " 2>/dev/null
2026-04-12 19:35:40 +04:00
ip rule del fwmark " $TPROXY_MARK " table $RT_TABLE 2>/dev/null
ip route del local default dev lo table $RT_TABLE 2>/dev/null
2026-02-14 19:52:31 +04:00
/etc/init.d/dnsmasq restart
2026-04-13 13:50:57 +04:00
_log "main: service stopped" "info"
2026-02-14 19:52:31 +04:00
}
case " $1 " in
2026-04-12 19:35:40 +04:00
start) export SKIP_URL = 0 FULL_LOAD = 1; _run "start" ;;
stop) _stop ;;
restart) _stop; export SKIP_URL = 0 FULL_LOAD = 1; _run "restart" ;;
reload) export SKIP_URL = 1 FULL_LOAD = 0; _run "reload" ;;
update) export SKIP_URL = 0 FULL_LOAD = 0; _run "update" ;;
*) echo "Usage: $0 {start|stop|restart|reload|update}" ; exit 1 ;;
2026-04-11 18:05:21 +04:00
esac