small-package/luci-app-openclash/root/etc/init.d/openclash

2408 lines
94 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh /etc/rc.common
# Copyright (c) 2019 vernesong
START=99
STOP=15
. $IPKG_INSTROOT/usr/share/openclash/openclash_ps.sh
. $IPKG_INSTROOT/usr/share/openclash/ruby.sh
. $IPKG_INSTROOT/usr/share/openclash/log.sh
[ -f /etc/openwrt_release ] && {
RAW_CONFIG_FILE=$(uci -q get openclash.config.config_path)
BACKUP_FILE="/etc/openclash/backup/$(uci -q get openclash.config.config_path |awk -F '/' '{print $5}' 2>/dev/null)"
CONFIG_FILE="/etc/openclash/$(uci -q get openclash.config.config_path |awk -F '/' '{print $5}' 2>/dev/null)"
}
LOGTIME=$(echo $(date "+%Y-%m-%d %H:%M:%S"))
CLASH="/etc/openclash/clash"
CLASH_CONFIG="/etc/openclash"
CRON_FILE="/etc/crontabs/root"
CACHE_PATH_OLD="/etc/openclash/.cache"
CACHE_PATH="/etc/openclash/cache.db"
LOG_FILE="/tmp/openclash.log"
START_LOG="/tmp/openclash_start.log"
RULE_PROVIDER_FILE="/tmp/yaml_rule_provider.yaml"
DNS_FILE="/tmp/yaml_dns.yaml"
GAME_RULE_FILE="/tmp/yaml_game_rule.yaml"
FALLBACK_FILTER_FILE="/etc/openclash/custom/openclash_custom_fallback_filter.yaml"
LOCK_FILE=/tmp/lock/openclash.lock
PROXY_FWMARK="0x162"
PROXY_ROUTE_TABLE="0x162"
set_lock() {
exec 888>"$LOCK_FILE" 2>/dev/null
flock -x 888 2>/dev/null
}
del_lock() {
flock -u 888 2>/dev/null
rm -rf "$LOCK_FILE"
}
add_cron()
{
[ "$(tail -n1 /etc/crontabs/root | wc -l)" -eq 0 ] && [ -n "$(cat /etc/crontabs/root 2>/dev/null)" ] && echo >> /etc/crontabs/root
[ -z "$(grep "openclash.sh" "$CRON_FILE" 2>/dev/null)" ] && {
[ "$(uci -q get openclash.config.auto_update)" -eq 1 ] && [ "$(uci -q get openclash.config.config_auto_update_mode)" -ne 1 ] && echo "0 $(uci -q get openclash.config.auto_update_time) * * $(uci -q get openclash.config.config_update_week_time) /usr/share/openclash/openclash.sh" >> $CRON_FILE
}
[ -z "$(grep "openclash_rule.sh" "$CRON_FILE" 2>/dev/null)" ] && {
[ "$(uci -q get openclash.config.other_rule_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.other_rule_update_day_time) * * $(uci -q get openclash.config.other_rule_update_week_time) /usr/share/openclash/openclash_rule.sh" >> $CRON_FILE
}
[ -z "$(grep "openclash_ipdb.sh" "$CRON_FILE" 2>/dev/null)" ] && {
[ "$(uci -q get openclash.config.geo_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.geo_update_day_time) * * $(uci -q get openclash.config.geo_update_week_time) /usr/share/openclash/openclash_ipdb.sh" >> $CRON_FILE
}
[ -z "$(grep "openclash_chnroute.sh" "$CRON_FILE" 2>/dev/null)" ] && {
[ "$(uci -q get openclash.config.chnr_auto_update)" -eq 1 ] && echo "0 $(uci -q get openclash.config.chnr_update_day_time) * * $(uci -q get openclash.config.chnr_update_week_time) /usr/share/openclash/openclash_chnroute.sh" >> $CRON_FILE
}
[ -z "$(grep "/etc/init.d/openclash" "$CRON_FILE" 2>/dev/null)" ] && {
[ "$(uci -q get openclash.config.auto_restart)" -eq 1 ] && echo "0 $(uci -q get openclash.config.auto_restart_day_time) * * $(uci -q get openclash.config.auto_restart_week_time) /etc/init.d/openclash restart 2>/dev/null" >> $CRON_FILE
}
crontab $CRON_FILE
nohup /usr/share/openclash/openclash_watchdog.sh &
}
del_cron()
{
sed -i '/openclash.sh/d' $CRON_FILE 2>/dev/null
sed -i '/openclash_rule.sh/d' $CRON_FILE 2>/dev/null
sed -i '/openclash_ipdb.sh/d' $CRON_FILE 2>/dev/null
sed -i '/openclash_chnroute.sh/d' $CRON_FILE 2>/dev/null
/etc/init.d/cron restart
}
change_dns() {
if [ "$1" -eq 1 ]; then
uci -q del dhcp.@dnsmasq[-1].server
uci -q add_list dhcp.@dnsmasq[0].server=127.0.0.1#"$dns_port"
uci -q delete dhcp.@dnsmasq[0].resolvfile
uci -q set dhcp.@dnsmasq[0].noresolv=1
uci -q set openclash.config.redirect_dns=1
else
uci -q set openclash.config.redirect_dns=0
fi
if [ "$2" -eq 1 ]; then
uci -q set dhcp.@dnsmasq[0].cachesize=0
fi
if [ "$ipv6_dns" == 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
#dnsmasq answer ipv6
uci -q set dhcp.@dnsmasq[0].filter_aaaa=0
fi
uci -q commit dhcp
uci -q commit openclash
/usr/share/openclash/openclash_custom_domain_dns.sh >/dev/null 2>&1
}
revert_dns() {
[ "$1" -eq 1 ] && {
uci -q del_list dhcp.@dnsmasq[0].server=127.0.0.1#"$3"
}
[ "$1" -eq 1 ] && [ "$4" -eq 0 ] && {
uci -q set openclash.config.redirect_dns=0
}
[ "$(uci -q get dhcp.@dnsmasq[0].cachesize)" = "0" ] && {
uci -q delete dhcp.@dnsmasq[0].cachesize
}
[ "$1" -eq 1 ] && {
if [ -n "$5" ]; then
uci -q set dhcp.@dnsmasq[0].resolvfile="$5"
elif [ -s "/tmp/resolv.conf.d/resolv.conf.auto" ] && [ -n "$(grep "nameserver" /tmp/resolv.conf.d/resolv.conf.auto)" ]; then
uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.d/resolv.conf.auto
elif [ -s "/tmp/resolv.conf.auto" ] && [ -n "$(grep "nameserver" /tmp/resolv.conf.auto)" ]; then
uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto
else
rm -rf /tmp/resolv.conf.auto
touch /tmp/resolv.conf.auto 2>/dev/null
cat >> "/tmp/resolv.conf.auto" <<-EOF
# Interface lan
nameserver 114.114.114.114
nameserver 119.29.29.29
EOF
uci -q set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto
fi
uci -q set dhcp.@dnsmasq[0].noresolv=0
}
uci -q commit dhcp
uci -q commit openclash
rm -rf /tmp/dnsmasq.d/dnsmasq_openclash.conf
rm -rf /tmp/dnsmasq.d/dnsmasq_openclash_custom_domain.conf
}
kill_clash()
{
clash_pids=$(pidof clash |sed 's/$//g')
for clash_pid in $clash_pids; do
kill -9 "$clash_pid" 2>/dev/null
done >/dev/null 2>&1
}
start_fail()
{
kill_clash
stop
del_lock
exit 0
}
yml_dns_check()
{
#检查DNS服务
if [ -z "$(ruby_read "$1" "['dns']['nameserver']")" ]; then
LOG_OUT "Detected That The nameserver DNS Option Has No Server Set, Starting To Complete..."
echo " nameserver:" > "$DNS_FILE" 2>/dev/null
cat >> "$DNS_FILE" <<-EOF
- 114.114.114.114
- 119.29.29.29
- 223.5.5.5
fallback:
- https://dns.cloudflare.com/dns-query
- https://public.dns.iij.jp/dns-query
- https://jp.tiar.app/dns-query
- https://jp.tiarap.org/dns-query
- tls://dot.tiar.app
EOF
if [ -z "$(ruby_read "$1" "['dns']")" ]; then
ruby_cover "$1" "['dns']" "$DNS_FILE"
else
ruby_merge "$1" "['dns']" "$DNS_FILE"
fi
fi
#default-nameserver
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$1');
reg = /^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(?::(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$/;
reg6 = /^(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))|\[(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))\](?::(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$/i;
if Value['dns'].has_key?('fallback') then
Value_1=Value['dns']['nameserver'] | Value['dns']['fallback']
else
Value_1=Value['dns']['nameserver']
end;
Value_1.each{|x|
if x =~ reg or x =~ reg6 then
if Value['dns'].has_key?('default-nameserver') then
Value['dns']['default-nameserver']=Value['dns']['default-nameserver'].to_a.insert(-1,x).uniq
else
Value_2={'default-nameserver'=>[x]}
Value['dns'].merge!(Value_2)
end
end
};
File.open('${1}','w') {|f| YAML.dump(Value, f)};
rescue Exception => e
puts '${LOGTIME} Error: Set default-nameserver Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
#fallback-filter
if [ "$custom_fallback_filter" = "1" ]; then
if [ -z "$(ruby_read "$CONFIG_FILE" "['dns']['fallback']")" ]; then
LOG_OUT "Error: Fallback-Filter Need fallback of DNS Been Setted, Ignore..."
return
fi
if [ -z "$(ruby_read "$2" "['fallback-filter']")" ]; then
LOG_OUT "Error: Unable To Parse Custom Fallback-Filter File, Ignore..."
return
fi
ruby_merge "$CONFIG_FILE" "['dns']" "$2"
fi
}
#Vmess-ws旧格式兼容不支持proxy-provider
yml_vmess_compatible()
{
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$1');
if Value.key?('$2') then
Value_1 = Marshal.load(Marshal.dump(Value['$2']));
Value['$2'].each{
|x|
if x['type'] != 'vmess' then
next
end;
if x.key?('ws-path') then
if not x.key?('ws-opts') then
x['ws-opts'] = {'path'=>x['ws-path'].to_s}
else
if x['ws-opts'].nil? then
x['ws-opts'] = {'path'=>x['ws-path'].to_s}
elsif x['ws-opts']['path'].nil? then
x['ws-opts'].update({'path'=>x['ws-path'].to_s})
else
x['ws-opts']['path'].update(x['ws-path'].to_s)
end
end
x.delete('ws-path')
end;
if x.key?('ws-headers') then
x['ws-headers'].keys.each{
|v|
if not x.key?('ws-opts') then
x['ws-opts'] = {'headers'=>{v.to_s=>x['ws-headers'][v].to_s}}
else
if x['ws-opts'].nil? then
x['ws-opts'] = {'headers'=>{v.to_s=>x['ws-headers'][v].to_s}}
elsif x['ws-opts']['headers'].nil? then
x['ws-opts'].update({'headers'=>{v.to_s=>x['ws-headers'][v].to_s}})
else
x['ws-opts']['headers'].update({v.to_s=>x['ws-headers'][v].to_s})
end
end
};
x.delete('ws-headers')
end;
};
if not Value_1.eql?(Value['$2']) then
File.open('$1','w') {|f| YAML.dump(Value, f)}
end;
end;
rescue Exception => e
puts '${LOGTIME} Error: Edit Vmess compatible Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
}
#修改集路径
yml_provider_path()
{
#provider_num=$(ruby_read "$1" "['$2'].count")
#local i=0
#while [ $i -le "$provider_num" ]
#do
# provider_path=$(ruby_read "$1" "['$2'].values[$i]['path']")
# if [ "$(echo "$provider_path" |awk -F '/' '{print $(NF-1)}')" != "$3" ]; then
# provider_name=$(echo "$provider_path" |awk -F '/' '{print $NF}')
# ruby_edit "$1" "['$2'].values[$i]['path']='./${3}/${provider_name}'"
# uci set openclash.config.config_reload=0 2>/dev/null
# uci commit openclash
# fi
# let i++
#done
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$1');
if Value.key?('$2') then
Value_1 = Marshal.load(Marshal.dump(Value['$2']));
Value['$2'].values.each{
|x,v|
if not x['path'].include? '$3' and not x['path'].include? 'game_rules' then
v=File.basename(x['path'])
x['path']='./$3/'+v
end
#CDN Replace
if '$4' != '0' then
if '$4' == 'https://cdn.jsdelivr.net/' then
if x['url'] and x['url'] =~ /^https:\/\/raw.githubusercontent.com/ then
x['url'] = 'https://cdn.jsdelivr.net/gh/' + x['url'].split('/')[3] + '/' + x['url'].split('/')[4] + '@' + x['url'].split(x['url'].split('/')[2] + '/' + x['url'].split('/')[3] + '/' + x['url'].split('/')[4] + '/')[1]
end
else
if x['url'] and x['url'] =~ /^https:\/\/(raw.|gist.)(githubusercontent.com|github.com)/ then
x['url'] = '$4' + x['url']
end
end
end
};
if not Value_1.eql?(Value['$2']) then
File.open('$1','w') {|f| YAML.dump(Value, f)}
end
end;
rescue Exception => e
puts '${LOGTIME} Error: Edit Provider Path Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
}
#检查集文件防止启动失败
yml_provider_check()
{
provider_path_line=$(ruby_read "$CONFIG_FILE" ".key?('$2')")
local provider_path_check provider_path_check_num=0
if "$provider_path_line"; then
while ( [ -n "$(pidof clash)" ] && [ "$provider_path_check_num" -le 5 ] )
do
provider_path_check=$(ruby -ryaml -E UTF-8 -e "
Value = YAML.load_file('$CONFIG_FILE');
Value['$2'].values.each{|x,v|
if not x['path'].empty? then
if x['path'].split('/')[0] == '.' then
v = '/etc/openclash/'+x['path'].split('./')[1]
else
v = x['path']
end
end;
if File::exist?(v) then
if not YAML.load_file(v).key?('$3') then
puts false
break
end
else
puts false
break
end
}
" 2>/dev/null)
if [ "$provider_path_check" = "false" ]; then
let provider_path_check_num++
sleep 2
else
break
fi
done
fi
if [ -z "$(pidof clash)" ] && [ -n "$provider_path_check" ]; then
if [ "$2" = "proxy-providers" ]; then
LOG_OUT "Error: Failed To Download Proxy-providers, Please Check The Log Page For Detailed error information!"
else
LOG_OUT "Error: Failed To Download Rule-providers, Please Check The Log Page For Detailed error information!"
fi
LOG_ALERT
start_fail
elif [ "$provider_path_check_num" -gt 5 ]; then
LOG_OUT "Warning: Providers File Check Timeout, If Failed To start, Please Check The Log Page For Detailed error information!"
sleep 3
fi
}
#获取DHCP或接口的DNS并追加
sys_dns_append()
{
if [ "$1" = 1 ]; then
wan_dns=$(/usr/share/openclash/openclash_get_network.lua "dns")
wan6_dns=$(/usr/share/openclash/openclash_get_network.lua "dns6")
wan_gate=$(/usr/share/openclash/openclash_get_network.lua "gateway")
wan6_gate=$(/usr/share/openclash/openclash_get_network.lua "gateway6")
dhcp_iface=$(/usr/share/openclash/openclash_get_network.lua "dhcp")
if [ -z "$dhcp_iface" ]; then
if [ -n "$wan_dns" ]; then
if [ -z "$(grep "^ \{0,\}nameserver:$" /tmp/yaml_config.namedns.yaml 2>/dev/null)" ]; then
echo " nameserver:" >/tmp/yaml_config.namedns.yaml
fi
for i in $wan_dns; do
echo " - \"$i\"" >>/tmp/yaml_config.namedns.yaml
done
fi
if [ -n "$wan6_dns" ] && [ "$2" = 1 ]; then
if [ -z "$(grep "^ \{0,\}nameserver:$" /tmp/yaml_config.namedns.yaml 2>/dev/null)" ]; then
echo " nameserver:" >/tmp/yaml_config.namedns.yaml
fi
for i in $wan6_dns; do
echo " - \"[${i}]:53\"" >>/tmp/yaml_config.namedns.yaml
done
fi
else
if [ -z "$(grep "^ \{0,\}nameserver:$" /tmp/yaml_config.namedns.yaml 2>/dev/null)" ]; then
echo " nameserver:" >/tmp/yaml_config.namedns.yaml
fi
if [ -n "$wan_gate" ]; then
for i in $wan_gate; do
echo " - \"$i\"" >>/tmp/yaml_config.namedns.yaml
done
fi
if [ -n "$wan6_gate" ] && [ "$2" = 1 ]; then
for i in $wan6_gate; do
echo " - \"[${i}]:53\"" >>/tmp/yaml_config.namedns.yaml
done
fi
for i in $dhcp_iface; do
echo " - dhcp://\"$i\"" >>/tmp/yaml_config.namedns.yaml
done
fi
fi
}
#获取自定义DNS设置
yml_dns_get()
{
local section="$1" regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
local enabled port type ip group dns_type dns_address
config_get_bool "enabled" "$section" "enabled" "1"
config_get "port" "$section" "port" ""
config_get "type" "$section" "type" ""
config_get "ip" "$section" "ip" ""
config_get "group" "$section" "group" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ -z "$ip" ]; then
return
fi
if [[ "$ip" =~ "$regex" ]]; then
ip="[${ip}]"
fi
if [ "$type" = "tcp" ]; then
dns_type="tcp://"
elif [ "$type" = "tls" ]; then
dns_type="tls://"
elif [ "$type" = "udp" ]; then
dns_type=""
elif [ "$type" = "https" ]; then
dns_type="https://"
fi
if [ -n "$port" ] && [ -n "$ip" ]; then
dns_address="$ip:$port"
elif [ -z "$port" ] && [ -n "$ip" ]; then
dns_address="$ip"
else
return
fi
if [ -n "$group" ]; then
if [ "$group" = "nameserver" ]; then
if [ -z "$(grep "^ \{0,\}nameserver:$" /tmp/yaml_config.namedns.yaml 2>/dev/null)" ]; then
echo " nameserver:" >/tmp/yaml_config.namedns.yaml
fi
echo " - \"$dns_type$dns_address\"" >>/tmp/yaml_config.namedns.yaml
else
if [ -z "$(grep "^ \{0,\}fallback:$" /tmp/yaml_config.falldns.yaml 2>/dev/null)" ]; then
echo " fallback:" >/tmp/yaml_config.falldns.yaml
fi
echo " - \"$dns_type$dns_address\"" >>/tmp/yaml_config.falldns.yaml
fi
else
return
fi
}
#添加自定义DNS设置
yml_dns_custom()
{
if [ "$1" = 1 ] || [ "$3" = 1 ]; then
sys_dns_append "$3" "$4"
config_load "openclash"
config_foreach yml_dns_get "dns_servers"
ruby_uniq "/tmp/yaml_config.namedns.yaml" "['nameserver']"
ruby_uniq "/tmp/yaml_config.falldns.yaml" "['fallback']"
if [ -f "/tmp/yaml_config.namedns.yaml" ]; then
if [ -z "$(ruby_read "$2" "['dns']")" ]; then
ruby_cover "$2" "['dns']" "/tmp/yaml_config.namedns.yaml"
ruby_merge "$2" "['dns']" "/tmp/yaml_config.falldns.yaml"
elif [ "$1" = 1 ]; then
ruby_edit "$2" "['dns'].delete('nameserver')"
ruby_edit "$2" "['dns'].delete('fallback')"
ruby_merge "$2" "['dns']" "/tmp/yaml_config.namedns.yaml"
ruby_merge "$2" "['dns']" "/tmp/yaml_config.falldns.yaml"
else
ruby_merge "$2" "['dns']" "/tmp/yaml_config.namedns.yaml"
fi
else
LOG_OUT "Error: Nameserver Option Must Be Setted, Stop Customing DNS Servers"
fi
fi
}
#获取认证信息
yml_auth_get()
{
local section="$1"
local enabled username password
config_get_bool "enabled" "$section" "enabled" "1"
config_get "username" "$section" "username" ""
config_get "password" "$section" "password" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ -z "$username" ] || [ -z "$password" ]; then
return
else
echo " - $username:$password" >>/tmp/config.auth
fi
}
#添加认证信息
yml_auth_custom()
{
if [ -n "$(ruby_read "$1" "['authentication']")" ]; then
ruby_edit "$1" ".delete('authentication')"
fi
if [ -f /tmp/config.auth ]; then
sed -i '/^dns:/i\authentication:' "$1" 2>/dev/null
ruby_cover "$1" "['authentication']" "/tmp/config.auth"
rm -rf /tmp/config.auth 2>/dev/null
fi
}
#Tolerance
yml_tolerance_set()
{
if [ -n "$tolerance" ] && [ "$tolerance" -ne 0 ]; then
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('${1}');
Value['proxy-groups'].each{
|x|
if x['type'] == 'url-test' then
x['tolerance']=${2}
end
};
File.open('${1}','w') {|f| YAML.dump(Value, f)};
rescue Exception => e
puts '${LOGTIME} Error: Set Url-Test Group Tolerance Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
fi
}
get_rule_file()
{
if [ -z "$1" ]; then
return
fi
GAME_RULE_FILE_NAME=$(grep "^$1," /usr/share/openclash/res/game_rules.list |awk -F ',' '{print $3}' 2>/dev/null)
if [ -z "$GAME_RULE_FILE_NAME" ]; then
GAME_RULE_FILE_NAME=$(grep "^$1," /usr/share/openclash/res/game_rules.list |awk -F ',' '{print $2}' 2>/dev/null)
fi
GAME_RULE_PATH="./game_rules/$GAME_RULE_FILE_NAME"
[ ! -f "$GAME_RULE_FILE" ] && echo "rules:" > "$GAME_RULE_FILE"
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$GAME_RULE_FILE');
if Value.has_key?('rules') and not Value['rules'].to_a.empty? then
Value['rules'].insert(-1,'RULE-SET,${1},${2}')
Value['rules']=Value['rules'].uniq
else
Value={'rules'=>['RULE-SET,${1},${2}']}
end;
Value_1={'rule-providers'=>{'${1}'=>{'type'=>'file', 'behavior'=>'ipcidr', 'path'=>'${GAME_RULE_PATH}'}}};
if Value.has_key?('rule-providers') and not Value['rule-providers'].to_a.empty? then
Value['rule-providers'].merge!(Value_1['rule-providers'])
Value['rule-providers'].uniq
else
Value['rule-providers']=Value_1['rule-providers']
end;
File.open('$GAME_RULE_FILE','w') {|f| YAML.dump(Value, f)};
rescue Exception => e
puts '${LOGTIME} Error: Game Rule Merge Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
}
yml_game_rule_get()
{
local section="$1"
local enabled group config
config_get_bool "enabled" "$section" "enabled" "1"
config_get "group" "$section" "group" ""
config_get "config" "$section" "config" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ -n "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
fi
if [ -z "$group" ]; then
return
fi
config_list_foreach "$section" "rule_name" get_rule_file "$group"
}
yml_rule_group_get()
{
local section="$1"
local enabled group config
config_get_bool "enabled" "$section" "enabled" "1"
config_get "group" "$section" "group" ""
config_get "config" "$section" "config" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ -n "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
fi
if [ -z "$group" ] || [ "$group" = "DIRECT" ] || [ "$group" = "REJECT" ]; then
return
fi
/usr/share/openclash/yml_groups_set.sh >/dev/null 2>&1 "$group"
}
yml_game_custom()
{
#处理游戏规则
config_load "openclash"
config_foreach yml_game_rule_get "game_config"
[ -f "$GAME_RULE_FILE" ] && {
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$CONFIG_FILE');
Value_1 = YAML.load_file('$GAME_RULE_FILE');
if Value.has_key?('rules') and not Value['rules'].to_a.empty? then
ruby_add_index = Value['rules'].index(Value['rules'].grep(/(GEOIP|MATCH|FINAL)/).first)
ruby_add_index ||= -1
Value_2 = Value_1['rules'].reverse!
Value_2.each{|x| Value['rules'].insert(ruby_add_index,x)}
Value['rules']=Value['rules'].uniq;
else
Value['rules'] = Value_1['rules']
end;
if Value.has_key?('rule-providers') and not Value['rule-providers'].to_a.empty? then
Value['rule-providers'].merge!(Value_1['rule-providers'])
Value['rule-providers'].uniq
else
Value['rule-providers']=Value_1['rule-providers']
end;
File.open('$CONFIG_FILE','w') {|f| YAML.dump(Value, f)}
rescue Exception => e
puts '${LOGTIME} Error: Game Rule Merge Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
}
#处理游戏节点与策略组
config_load "openclash"
config_foreach yml_rule_group_get "rule_provider_config"
config_foreach yml_rule_group_get "rule_providers"
config_foreach yml_rule_group_get "game_config"
if [ -f "/tmp/yaml_groups.yaml" ] || [ -f "/tmp/yaml_servers.yaml" ] || [ -f "/tmp/yaml_provider.yaml" ]; then
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$CONFIG_FILE');
if File::exist?('/tmp/yaml_groups.yaml') then
Value_1 = YAML.load_file('/tmp/yaml_groups.yaml');
if Value.has_key?('proxy-groups') and not Value['proxy-groups'].to_a.empty? then
Value['proxy-groups'] = Value['proxy-groups']+Value_1
Value['proxy-groups'].uniq
else
Value['proxy-groups']=Value_1
end
end;
if File::exist?('/tmp/yaml_servers.yaml') then
Value_2 = YAML.load_file('/tmp/yaml_servers.yaml');
if Value.has_key?('proxies') and not Value['proxies'].to_a.empty? then
Value['proxies'] = Value['proxies']+Value_2['proxies']
Value['proxies'].uniq
else
Value['proxies']=Value_2['proxies']
end
end;
if File::exist?('/tmp/yaml_provider.yaml') then
Value_3 = YAML.load_file('/tmp/yaml_provider.yaml');
if Value.has_key?('proxy-providers') and not Value['proxy-providers'].to_a.empty? then
Value['proxy-providers'].merge!(Value_3['proxy-providers'])
Value['proxy-providers'].uniq
else
Value['proxy-providers']=Value_3['proxy-providers']
end
end;
File.open('$CONFIG_FILE','w') {|f| YAML.dump(Value, f)}
rescue Exception => e
puts '${LOGTIME} Error: Game Proxy Merge Error,【' + e.message + '】'
end" 2>/dev/null >> $LOG_FILE
fi
}
yml_rule_set_add()
{
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$CONFIG_FILE');
if $3 == 1 then
if Value.has_key?('rule-set-bottom') and not Value['rule-set-bottom'].to_a.empty? then
Value['rule-set-bottom'].insert(-1,'RULE-SET,${1},${2}')
else
Value_1 = {'rule-set-bottom'=>['RULE-SET,${1},${2}']}
Value.merge!(Value_1);
end
Value['rule-set-bottom'] = Value['rule-set-bottom'].uniq
else
if Value.has_key?('rule-set-top') and not Value['rule-set-top'].to_a.empty? then
Value['rule-set-top'].insert(-1,'RULE-SET,${1},${2}')
else
Value_1 = {'rule-set-top'=>['RULE-SET,${1},${2}']}
Value.merge!(Value_1);
end
Value['rule-set-top'] = Value['rule-set-top'].uniq
end
File.open('$CONFIG_FILE','w') {|f| YAML.dump(Value, f)}
rescue Exception => e
puts '${LOGTIME} Error: Rule Set Add Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
}
yml_gen_rule_provider_file()
{
if [ -z "$1" ]; then
return
fi
RULE_PROVIDER_FILE_NAME=$(grep "^$1," /usr/share/openclash/res/rule_providers.list |awk -F ',' '{print $6}' 2>/dev/null)
if [ -z "$RULE_PROVIDER_FILE_NAME" ]; then
RULE_PROVIDER_FILE_NAME=$(grep "^$1," /usr/share/openclash/res/rule_providers.list |awk -F ',' '{print $5}' 2>/dev/null)
fi
RULE_PROVIDER_FILE_BEHAVIOR=$(grep ",$RULE_PROVIDER_FILE_NAME$" /usr/share/openclash/res/rule_providers.list |awk -F ',' '{print $3}' 2>/dev/null)
RULE_PROVIDER_FILE_PATH="/etc/openclash/rule_provider/$RULE_PROVIDER_FILE_NAME"
RULE_PROVIDER_FILE_URL_PATH="$(grep ",$RULE_PROVIDER_FILE_NAME$" /usr/share/openclash/res/rule_providers.list |awk -F ',' '{print $4$5}' 2>/dev/null)"
if [ "$github_address_mod" -eq 0 ]; then
RULE_PROVIDER_FILE_URL="https://raw.githubusercontent.com/${RULE_PROVIDER_FILE_URL_PATH}"
else
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ]; then
RULE_PROVIDER_FILE_URL="https://cdn.jsdelivr.net/gh/"$(echo "$RULE_PROVIDER_FILE_URL_PATH" |awk -F '/master' '{print $1}' 2>/dev/null)"@master"$(echo "$RULE_PROVIDER_FILE_URL_PATH" |awk -F 'master' '{print $2}')""
else
RULE_PROVIDER_FILE_URL="${github_address_mod}https://raw.githubusercontent.com/${RULE_PROVIDER_FILE_URL_PATH}"
fi
fi
if [ -n "$(grep "$RULE_PROVIDER_FILE_URL" $RULE_PROVIDER_FILE 2>/dev/null)" ]; then
return
fi
cat >> "$RULE_PROVIDER_FILE" <<-EOF
$1:
type: http
behavior: $RULE_PROVIDER_FILE_BEHAVIOR
path: $RULE_PROVIDER_FILE_PATH
url: $RULE_PROVIDER_FILE_URL
EOF
if [ -z "$3" ]; then
cat >> "$RULE_PROVIDER_FILE" <<-EOF
interval=86400
EOF
else
cat >> "$RULE_PROVIDER_FILE" <<-EOF
interval: $3
EOF
fi
yml_rule_set_add "$1" "$2" "$4"
}
yml_get_rule_provider()
{
local section="$1"
local enabled group config interval position
config_get_bool "enabled" "$section" "enabled" "1"
config_get "group" "$section" "group" ""
config_get "config" "$section" "config" ""
config_get "interval" "$section" "interval" ""
config_get "position" "$section" "position" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ -n "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
fi
if [ -z "$group" ]; then
return
fi
config_list_foreach "$section" "rule_name" yml_gen_rule_provider_file "$group" "$interval" "$position"
}
#处理自定义规则集
yml_set_custom_rule_provider()
{
local section="$1"
local enabled name config type behavior path url interval group position
config_get_bool "enabled" "$section" "enabled" "1"
config_get "name" "$section" "name" ""
config_get "config" "$section" "config" ""
config_get "type" "$section" "type" ""
config_get "behavior" "$section" "behavior" ""
config_get "path" "$section" "path" ""
config_get "url" "$section" "url" ""
config_get "interval" "$section" "interval" ""
config_get "group" "$section" "group" ""
config_get "position" "$section" "position" ""
if [ "$enabled" = "0" ]; then
return
fi
if [ -n "$(grep "$url" "$RULE_PROVIDER_FILE" 2>/dev/null)" ] && [ -n "$url" ]; then
return
fi
if [ -n "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
return
fi
if [ -z "$name" ] || [ -z "$type" ] || [ -z "$behavior" ]; then
return
fi
if [ "$type" = "http" ] && [ -z "$url" ]; then
return
fi
if [ "$path" != "./rule_provider/$name.yaml" ] && [ "$type" = "http" ]; then
path="./rule_provider/$name.yaml"
elif [ -z "$path" ]; then
return
fi
if [ -n "$(grep "$path" "$RULE_PROVIDER_FILE" 2>/dev/null)" ]; then
return
fi
if [ -z "$interval" ] && [ "$type" = "http" ]; then
interval=86400
fi
cat >> "$RULE_PROVIDER_FILE" <<-EOF
$name:
type: $type
behavior: $behavior
path: $path
EOF
if [ "$type" = "http" ]; then
cat >> "$RULE_PROVIDER_FILE" <<-EOF
url: $url
interval: $interval
EOF
fi
yml_rule_set_add "$name" "$group" "$position"
}
#处理规则集
yml_custom_rule_provider()
{
config_load "openclash"
config_foreach yml_get_rule_provider "rule_provider_config"
config_foreach yml_set_custom_rule_provider "rule_providers"
if [ -f "$RULE_PROVIDER_FILE" ]; then
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$CONFIG_FILE');
rescue Exception => e
puts '${LOGTIME} Error: Load File Error,【' + e.message + '】'
end;
begin
Value_1 = YAML.load_file('$RULE_PROVIDER_FILE');
if Value.has_key?('rule-providers') and not Value['rule-providers'].to_a.empty? then
Value['rule-providers'].merge!(Value_1)
else
Value['rule-providers']=Value_1
end;
rescue Exception => e
puts '${LOGTIME} Error: Custom Rule Provider Merge Error,【' + e.message + '】'
end;
begin
if Value.has_key?('rules') and not Value['rules'].to_a.empty? then
if Value.has_key?('rule-set-bottom') and not Value['rule-set-bottom'].to_a.empty? then
if $enable_rule_proxy != 1 then
ruby_add_index = Value['rules'].index(Value['rules'].grep(/(GEOIP|MATCH|FINAL)/).first)
else
if Value['rules'].grep(/GEOIP/)[0].nil? or Value['rules'].grep(/GEOIP/)[0].empty? then
ruby_add_index = Value['rules'].index(Value['rules'].grep(/DST-PORT,80/).last)
ruby_add_index ||= Value['rules'].index(Value['rules'].grep(/(MATCH|FINAL)/).first)
else
ruby_add_index = Value['rules'].index(Value['rules'].grep(/GEOIP/).first)
end
end
ruby_add_index ||= -1
Value['rule-set-bottom'].reverse.each{|x| Value['rules'].insert(ruby_add_index,x)}
Value.delete('rule-set-bottom')
end
if Value.has_key?('rule-set-top') and not Value['rule-set-top'].to_a.empty? then
if Value['rules'].to_a.grep(/(?=.*198.18.0)(?=.*REJECT)/).empty? then
Value['rule-set-top'].reverse.each{|x| Value['rules'].insert(0,x)}
else
ruby_add_index = Value['rules'].index(Value['rules'].grep(/(?=.*198.18.0)(?=.*REJECT)/).first)
Value['rule-set-top'].reverse.each{|x| Value['rules'].insert(ruby_add_index + 1,x)}
end
Value.delete('rule-set-top')
end
else
if Value.has_key?('rule-set-top') and not Value['rule-set-top'].to_a.empty? then
Value['rules'] = Value['rule-set-top']
Value.delete('rule-set-top')
end
if Value.has_key?('rule-set-bottom') and not Value['rule-set-bottom'].to_a.empty? then
if Value.has_key?('rule-set-top') and not Value['rule-set-top'].to_a.empty? then
Value['rules'] = Value['rules'] | Value['rule-set-bottom']
else
Value['rules'] = Value['rule-set-bottom']
end
Value.delete('rule-set-bottom')
end
end;
rescue Exception => e
puts '${LOGTIME} Error: Rule Set Add Error,【' + e.message + '】'
ensure
File.open('$CONFIG_FILE','w') {|f| YAML.dump(Value, f)}
end;
" 2>/dev/null >> $LOG_FILE
fi
}
#获取订阅配置
sub_info_get()
{
local section="$1" address enabled name
config_get_bool "enabled" "$section" "enabled" "1"
config_get "address" "$section" "address" ""
config_get "name" "$section" "name" ""
if [ "$subscribe_enable" = "1" ]; then
return
fi
if [ "$enabled" -eq 0 ]; then
return
fi
if [ -z "$address" ]; then
return
fi
if [ -z "$name" ]; then
CONFIG_NAME="config"
RAW_CONFIG_FILE="/etc/openclash/config/config.yaml"
CONFIG_FILE="/etc/openclash/config.yaml"
else
CONFIG_NAME="$name"
RAW_CONFIG_FILE="/etc/openclash/config/$name.yaml"
CONFIG_FILE="/etc/openclash/$name.yaml"
fi
uci -q set openclash.config.config_path="$RAW_CONFIG_FILE"
uci -q commit openclash
subscribe_enable=1
}
#配置文件选择
config_choose()
{
if [ -z "$RAW_CONFIG_FILE" ] || [ ! -f "$RAW_CONFIG_FILE" ]; then
CONFIG_NAME=$(ls -lt /etc/openclash/config/ | grep -E '.yaml|.yml' | head -n 1 |awk '{print $9}')
if [ -n "$CONFIG_NAME" ]; then
uci -q set openclash.config.config_path="/etc/openclash/config/$CONFIG_NAME"
uci -q commit openclash
RAW_CONFIG_FILE="/etc/openclash/config/$CONFIG_NAME"
CONFIG_FILE="/etc/openclash/$CONFIG_NAME"
fi
fi 2>/dev/null
CONFIG_NAME=$(echo "$RAW_CONFIG_FILE" |awk -F '/' '{print $5}' 2>/dev/null)
HISTORY_PATH_OLD="/etc/openclash/history/${CONFIG_NAME%.*}"
HISTORY_PATH="/etc/openclash/history/${CONFIG_NAME%.*}.db"
if [ ! -f "$RAW_CONFIG_FILE" ]; then
config_load "openclash"
config_foreach sub_info_get "config_subscribe"
subscribe_auto_update=$(uci get openclash.config.auto_update 2>/dev/null)
if [ "$subscribe_enable" = "1" ] && [ "$subscribe_auto_update" -eq 1 ]; then
LOG_OUT "Config File Does Not Exist, You Have Set Subscription Information, Ready To Download..."
nohup /usr/share/openclash/openclash.sh &
del_lock
exit 0
else
LOG_OUT "Error: Config Not Found"
sleep 3
del_lock
exit 0
fi
fi
}
config_check()
{
#创建启动配置
#rm -rf "/etc/openclash/*.y*" 2>/dev/null
cp "$RAW_CONFIG_FILE" "$CONFIG_FILE"
ruby -ryaml -E UTF-8 -e "
begin
YAML.load_file('$RAW_CONFIG_FILE');
rescue Exception => e
puts '${LOGTIME} Error: Unable To Parse Config File,【' + e.message + '】'
system 'rm -rf ${CONFIG_FILE}'
end
" 2>/dev/null >> $LOG_FILE
if [ $? -ne 0 ]; then
LOG_OUT "Error: Ruby Works Abnormally, Please Check The Ruby Library Depends!"
sleep 3
start_fail
elif [ ! -f "$CONFIG_FILE" ] || [ ! -s "$CONFIG_FILE" ]; then
LOG_OUT "Error: Config File Format Validation Failed..."
sleep 3
start_fail
fi
#检查field名称不兼容旧写法
ruby -ryaml -E UTF-8 -e "
Value = YAML.load_file('$CONFIG_FILE');
if Value.key?('Proxy') or Value.key?('Proxy Group') or Value.key?('Rule') or Value.key?('rule-provider') then
if Value.key?('Proxy') then
Value['proxies'] = Value['Proxy']
Value.delete('Proxy')
puts '${LOGTIME} Warning: Proxy is no longer used. Auto replaced by proxies'
end
if Value.key?('Proxy Group') then
Value['proxy-groups'] = Value['Proxy Group']
Value.delete('Proxy Group')
puts '${LOGTIME} Warning: Proxy Group is no longer used. Auto replaced by proxy-groups'
end
if Value.key?('Rule') then
Value['rules'] = Value['Rule']
Value.delete('Rule')
puts '${LOGTIME} Warning: Rule is no longer used. Auto replaced by rules'
end
if Value.key?('rule-provider') then
Value['rule-providers'] = Value['rule-provider']
Value.delete('rule-provider')
puts '${LOGTIME} Warning: rule-provider is no longer used. Auto replaced by rule-providers'
end;
File.open('$CONFIG_FILE','w') {|f| YAML.dump(Value, f)};
end;
" 2>/dev/null >> $LOG_FILE
}
yml_other_rules_get()
{
local section="$1"
local enabled config
config_get_bool "enabled" "$section" "enabled" "1"
config_get "config" "$section" "config" ""
if [ "$enabled" = "0" ] || [ "$config" != "$2" ]; then
return
fi
if [ -n "$rule_name" ]; then
return
fi
config_get "rule_name" "$section" "rule_name" ""
}
check_run_quick()
{
quick_start=true
check_file="$RAW_CONFIG_FILE /etc/openclash/custom/openclash_custom_domain_dns.list /etc/openclash/custom/openclash_custom_domain_dns_policy.list /etc/openclash/custom/openclash_custom_fake_filter.list /etc/openclash/custom/openclash_custom_fallback_filter.yaml /etc/openclash/custom/openclash_custom_hosts.list /etc/openclash/custom/openclash_custom_rules.list /etc/openclash/custom/openclash_custom_rules_2.list $dev_core_path $tun_core_path $geoip_path $chnr_path $chnr6_path /usr/share/openclash/res/ConnersHua.yaml /usr/share/openclash/res/ConnersHua_return.yaml /usr/share/openclash/res/lhie1.yaml /usr/share/openclash/res/openclash_version /tmp/openclash_fake_filter.list"
if [ ! -f "$CONFIG_FILE" ] || [ ! -f "/tmp/openclash_config.tmp" ] || [ ! -f "/tmp/openclash.change" ]; then
quick_start=false
return
fi
cmp -s "/etc/config/openclash" "/tmp/openclash_config.tmp"
if [ "$?" -ne "0" ]; then
LOG_OUT "Tip: Because of the file【 /etc/config/openclash 】modificated, Pause quick start..."
quick_start=false
else
if [ -s "/tmp/openclash.change" ]; then
for i in $check_file; do
if [ -z "$(grep "$i $(date -r $i)$" "/tmp/openclash.change")" ]; then
LOG_OUT "Tip: Because of the file【 $i 】modificated, Pause quick start..."
quick_start=false
break
fi
done 2>/dev/null
fi
fi
}
write_run_quick()
{
if ! $quick_start; then
cp "/etc/config/openclash" "/tmp/openclash_config.tmp"
: > "/tmp/openclash.change"
for i in $check_file; do
echo "$i $(date -r $i)" >> "/tmp/openclash.change"
done 2>/dev/null
fi
}
custom_rule_provider()
{
local section="$1"
local enabled config
config_get "config" "$section" "config" ""
config_get_bool "enabled" "$section" "enabled" "1"
if [ "$enabled" = "0" ]; then
return
fi
if [ "$config" = "all" ] || [ "$config" = "$CONFIG_NAME" ]; then
config_set_custom_rule_provider=1
fi
}
#运行模式处理
do_run_mode()
{
en_mode=$(uci -q get openclash.config.en_mode)
if [ "$en_mode" = "fake-ip-tun" ]; then
en_mode_tun="1"
en_mode="fake-ip"
fi
if [ "$en_mode" = "redir-host-tun" ]; then
en_mode_tun="1"
en_mode="redir-host"
fi
if [ "$en_mode" = "redir-host-mix" ]; then
en_mode_tun="2"
en_mode="redir-host"
fi
if [ "$en_mode" = "fake-ip-mix" ]; then
en_mode_tun="2"
en_mode="fake-ip"
fi
}
do_run_file()
{
#Some MIPS devices file system cound not use db
source "/etc/openwrt_release"
[ "$small_flash_memory" == "1" ] || [ -n "$(echo $core_version |grep mips)" ] || [ -n "$(echo $DISTRIB_ARCH |grep mips)" ] || [ -n "$(opkg status libc 2>/dev/null |grep 'Architecture' |awk -F ': ' '{print $2}' |grep mips)" ] && mkdir -p /tmp/etc/openclash && CACHE_PATH="/tmp/etc/openclash/cache.db"
if [ "$small_flash_memory" != "1" ]; then
dev_core_path="/etc/openclash/core/clash"
tun_core_path="/etc/openclash/core/clash_tun"
geoip_path="/etc/openclash/Country.mmdb"
chnr_path="/etc/openclash/china_ip_route.ipset"
chnr6_path="/etc/openclash/china_ip6_route.ipset"
mv "/tmp/etc/openclash/Country.mmdb" "$geoip_path" 2>/dev/null
mv "/tmp/etc/openclash/china_ip_route.ipset" "$chnr_path" 2>/dev/null
mv "/tmp/etc/openclash/china_ip6_route.ipset" "$chnr6_path" 2>/dev/null
mv "/tmp/etc/openclash/core/" "/etc/openclash" 2>/dev/null
if [ "$CACHE_PATH" != "/tmp/etc/openclash/cache.db" ]; then
rm -rf "/tmp/etc/openclash" 2>/dev/null
fi
else
dev_core_path="/tmp/etc/openclash/core/clash"
tun_core_path="/tmp/etc/openclash/core/clash_tun"
geoip_path="/tmp/etc/openclash/Country.mmdb"
chnr_path="/tmp/etc/openclash/china_ip_route.ipset"
chnr6_path="/tmp/etc/openclash/china_ip6_route.ipset"
[ ! -h "/etc/openclash/Country.mmdb" ] && mv "/etc/openclash/Country.mmdb" "$geoip_path" 2>/dev/null
[ ! -h "/etc/openclash/china_ip_route.ipset" ] && mv "/etc/openclash/china_ip_route.ipset" "$chnr_path" 2>/dev/null
[ ! -h "/etc/openclash/china_ip6_route.ipset" ] && mv "/etc/openclash/china_ip6_route.ipset" "$chnr6_path" 2>/dev/null
mv "/etc/openclash/core/" "/tmp/etc/openclash" 2>/dev/null
fi
rm -rf "/etc/openclash/cache.db" 2>/dev/null
rm -rf "/etc/openclash/clash" 2>/dev/null
if [ -n "$en_mode_tun" ]; then
ln -s "$tun_core_path" /etc/openclash/clash 2>/dev/null
core_type="TUN"
core_start_log="Tip: Detected The Exclusive Function of The TUN Core, Use TUN Core to Start..."
fi
if [ "$rule_source" != "0" ]; then
config_load "openclash"
config_foreach yml_other_rules_get "other_rules" "$CONFIG_NAME"
fi
config_load "openclash"
config_set_custom_rule_provider=0
for i in "rule_provider_config" "rule_provider_config" "rule_providers" "game_config"; do
config_foreach custom_rule_provider "$i"
if [ "$config_set_custom_rule_provider" -eq 1 ]; then
break
fi
done 2>/dev/null
if [ "$proxy_mode" = "script" ] || [ "$config_set_custom_rule_provider" -eq 1 ] || [ "$rule_name" = "ConnersHua" ] || [ "$rule_name" = "lhie1" ] || [ -n "$(ruby_read "$RAW_CONFIG_FILE" "['rules'].grep(/(^RULE-SET,|^SCRIPT,)/)")" ] || [ -n "$(ruby_read "/etc/openclash/custom/openclash_custom_rules.list" "['rules'].grep(/(^RULE-SET,|^SCRIPT,)/)")" ] || [ -n "$(ruby_read "/etc/openclash/custom/openclash_custom_rules_2.list" "['rules'].grep(/(^RULE-SET,|^SCRIPT,)/)")" ]; then
if [ -z "$en_mode_tun" ]; then
rm -rf "/etc/openclash/clash"
ln -s "$tun_core_path" /etc/openclash/clash 2>/dev/null
core_type="TUN"
core_start_log="Tip: Detected The Exclusive Function of The TUN Core, Use TUN Core to Start..."
fi
fi
if [ ! -f "/etc/openclash/clash" ] && [ -f "$dev_core_path" ] && [ -z "$core_type" ]; then
ln -s "$dev_core_path" /etc/openclash/clash 2>/dev/null
core_start_log="Tip: No Special Configuration Detected, Use Dev Core to Start..."
fi
if [ ! -f "/etc/openclash/clash" ] && [ -f "$tun_core_path" ]; then
ln -s "$tun_core_path" /etc/openclash/clash 2>/dev/null
core_type="TUN"
core_start_log="Tip: Detected that the Dev Core is not Installed, Use TUN Core to Start..."
fi
[ ! -f "$CLASH" ] && {
LOG_OUT "Tip: Detected that the Core is not Installed, Ready to Download..."
rm -rf "/tmp/clash_last_version"
/usr/share/openclash/openclash_core.sh "$core_type"
if [ "$core_type" == "TUN" ] && [ ! -f "$tun_core_path" ]; then
start_fail
elif [ -z "$core_type" ] && [ ! -f "$dev_core_path" ]; then
start_fail
else
del_lock
restart
exit 0
fi
}
[ ! -f "$geoip_path" ] && {
LOG_OUT "Tip: Detected that the GEOIP Database is not Installed, Ready to Download..."
/usr/share/openclash/openclash_ipdb.sh
}
if [ "$china_ip_route" = "1" ] || [ "$china_ip6_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
if [ ! -f "$chnr_path" ] || [ ! -f "$chnr6_path" ]; then
LOG_OUT "Tip: Detected that the Chnroute Cidr List is not Installed, Ready to Download..."
/usr/share/openclash/openclash_chnroute.sh
fi
fi
if [ ! -f "$chnr_path" ] || [ ! -f "$chnr6_path" ] || [ ! -f "$geoip_path" ]; then
start_fail
fi
[ ! -x "$tun_core_path" ] && chmod 4755 "$tun_core_path" 2>/dev/null
[ ! -x "$dev_core_path" ] && chmod 4755 "$dev_core_path" 2>/dev/null
#fake_ip_filter
if [ "$3" = "fake-ip" ]; then
if [ ! -f "/tmp/openclash_fake_filter.list" ] || [ -n "$(grep "config servers" /etc/config/openclash 2>/dev/null)" ]; then
/usr/share/openclash/openclash_fake_filter.sh
fi
if [ -s "/tmp/openclash_servers_fake_filter.conf" ]; then
mkdir -p /tmp/dnsmasq.d
cp /tmp/openclash_servers_fake_filter.conf /tmp/dnsmasq.d/dnsmasq_openclash.conf
fi
fi
[ -f "$geoip_path" ] && [ "$small_flash_memory" = "1" ] && {
ln -s "$geoip_path" /etc/openclash/Country.mmdb 2>/dev/null
}
[ -f "$chnr_path" ] && [ "$small_flash_memory" = "1" ] && {
ln -s "$chnr_path" /etc/openclash/china_ip_route.ipset 2>/dev/null
}
[ -f "$chnr6_path" ] && [ "$small_flash_memory" = "1" ] && {
ln -s "$chnr6_path" /etc/openclash/china_ip6_route.ipset 2>/dev/null
}
#Restore history cache
if [ -f "$HISTORY_PATH" ] && [ -f "$HISTORY_PATH_OLD" ]; then
if [ "$(date -r $HISTORY_PATH +%s)" -ge "$(date -r $HISTORY_PATH_OLD +%s)" ]; then
cmp -s "$CACHE_PATH" "$HISTORY_PATH"
if [ "$?" -ne "0" ]; then
if [ "$CACHE_PATH" != "/tmp/etc/openclash/cache.db" ]; then
ln -s "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
else
cp "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
fi
fi
else
cmp -s "$CACHE_PATH_OLD" "$HISTORY_PATH_OLD"
if [ "$?" -ne "0" ]; then
cp "$HISTORY_PATH_OLD" "$CACHE_PATH_OLD" 2>/dev/null
fi
fi
else
if [ -f "$HISTORY_PATH" ]; then
cmp -s "$CACHE_PATH" "$HISTORY_PATH"
if [ "$?" -ne "0" ]; then
if [ "$CACHE_PATH" != "/tmp/etc/openclash/cache.db" ]; then
ln -s "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
else
cp "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
fi
fi
fi
if [ -f "$HISTORY_PATH_OLD" ]; then
cmp -s "$CACHE_PATH_OLD" "$HISTORY_PATH_OLD"
if [ "$?" -ne "0" ]; then
cp "$HISTORY_PATH_OLD" "$CACHE_PATH_OLD" 2>/dev/null
fi
fi
fi
if [ "$CACHE_PATH" == "/tmp/etc/openclash/cache.db" ]; then
[ ! -f "$CACHE_PATH" ] && touch "$CACHE_PATH"
ln -s "$CACHE_PATH" /etc/openclash/cache.db 2>/dev/null
else
[ ! -f "$CACHE_PATH" ] && touch "$HISTORY_PATH"
ln -s "$HISTORY_PATH" "$CACHE_PATH" 2>/dev/null
fi
if [ -z "$_koolshare" ]; then
if ! capsh --is-uid=0 >/dev/null || ! capsh --has-ambient >/dev/null; then
LOG_OUT "Error: Could Not Load The Capsh Library, Please Verify The Capsh Shell Library Work Well"
LOG_OUT "Tip: You Could Download And Re-Install The libcap & libcap-bin Library From The Address Give"
echo "" >> $LOG_FILE
echo "---------- https://mirrors.cloud.tencent.com/lede/snapshots/packages/ ----------" >> $LOG_FILE
echo "" >> $LOG_FILE
sleep 3
start_fail
fi
fi
#创建原始备份
if [ ! -f "$2" ]; then
cp "$1" "$2"
fi
#保存启动内核类型
uci -q set openclash.config.core_type="$core_type"
uci -q commit openclash
}
#绑定interface防止回环
check_interface_name()
{
if [ -n "$interface_name" ] && [ "$interface_name" != "0" ]; then
ruby_edit "$CONFIG_FILE" "['interface-name']='$interface_name'"
else
sed -i "/^interface-name:/d" "$CONFIG_FILE" 2>/dev/null
fi
}
start_run_core()
{
LOG_OUT "$core_start_log"
ulimit -SHn 65535 2>/dev/null
ulimit -v unlimited 2>/dev/null
modprobe tun >/dev/null 2>&1
check_interface_name
config_reload=$(uci -q get openclash.config.config_reload)
if [ -n "$(pidof clash)" ] && [ "$core_type" != "TUN" ] && [ "$config_reload" != "0" ]; then
curl -s --connect-timeout 5 -m 5 -H 'Content-Type: application/json' -H "Authorization: Bearer ${da_password}" -XPUT http://"$lan_ip":"$cn_port"/configs -d "{\"path\": \"$CONFIG_FILE\"}" 2>/dev/null
else
kill_clash
if [ -z "$_koolshare" ]; then
#防止赋权失败
touch "/tmp/openclash.log" 2>/dev/null
chmod o+w /etc/openclash/proxy_provider/* 2>/dev/null
chmod o+w /etc/openclash/rule_provider/* 2>/dev/null
chmod o+w /tmp/openclash.log 2>/dev/null
chown nobody:nogroup /etc/openclash/core/* 2>/dev/null
#使用nobody启动内核方便代理路由自身流量
capabilties="cap_sys_resource,cap_dac_override,cap_net_raw,cap_net_bind_service,cap_net_admin"
capsh --caps="${capabilties}+eip" -- -c "capsh --user=nobody --addamb='${capabilties}' -- -c 'nohup $CLASH -d $CLASH_CONFIG -f \"$CONFIG_FILE\" >> $LOG_FILE 2>&1 &'" >> $LOG_FILE 2>&1
else
nohup $CLASH -d $CLASH_CONFIG -f "$CONFIG_FILE" >> $LOG_FILE 2>&1 &
fi
fi
uci -q set openclash.config.config_reload=1
uci -q commit openclash
}
check_core_status()
{
check_time=1
while ( [ "$check_time" -le 3 ] && [ -n "$(pidof clash)" ] )
do
sleep 1
let check_time++
done
if [ -z "$(pidof clash)" ]; then
LOG_ALERT
fi
}
#不修改配置文件启动
raw_config_start()
{
cp "$RAW_CONFIG_FILE" "$CONFIG_FILE"
dns_port=$(ruby_read "$CONFIG_FILE" "['dns']['listen'].split(':')[1]")
en_mode=$(ruby_read "$CONFIG_FILE" "['dns']['enhanced-mode']")
proxy_port=$(ruby_read "$CONFIG_FILE" "['redir-port']")
if [ -z "$dns_port" ] || [ -z "$en_mode" ] || [ -z "$proxy_port" ]; then
if [ -z "$dns_port" ]; then
LOG_OUT "Error: Get DNS 'listen' Option Error, OpenClash Can Not Start With Raw Config File"
sleep 2
fi
if [ -z "$en_mode" ]; then
LOG_OUT "Error: Get DNS 'enhanced-mode' Option Error, OpenClash Can Not Start With Raw Config File"
sleep 2
fi
if [ -z "$proxy_port" ]; then
LOG_OUT "Error: Get General 'redir-port' Option Error, OpenClash Can Not Start With Raw Config File"
sleep 2
fi
start_fail
fi
start_run_core
check_core_status
if ! pidof clash >/dev/null; then
LOG_OUT "Error: OpenClash Can Not Start, Please Check The Error Info And Try Again!"
sleep 3
start_fail
fi
if [ "$en_mode" = "redir-host" ]; then
case $en_mode_tun in
"1")
uci -q set openclash.config.en_mode=redir-host-tun
;;
"2")
uci -q set openclash.config.en_mode=redir-host-mix
;;
*)
uci -q set openclash.config.en_mode=redir-host
esac
elif [ "$en_mode" = "fake-ip" ]; then
case $en_mode_tun in
"1")
uci -q set openclash.config.en_mode=fake-ip-tun
;;
"2")
uci -q set openclash.config.en_mode=fake-ip-mix
;;
*)
uci -q set openclash.config.en_mode=fake-ip
esac
fi
dase=$(ruby_read "$CONFIG_FILE" "['secret']")
uci -q set openclash.config.dashboard_password="$dase"
cn_port=$(ruby_read "$CONFIG_FILE" "['external-controller'].split(':')[1]")
uci -q set openclash.config.cn_port="$cn_port"
uci -q set openclash.config.proxy_port="$proxy_port"
uci -q set openclash.config.restricted_mode=1
uci commit openclash
}
try_restore_start()
{
if [ -z "$(pidof clash)" ]; then
if [ "$rule_source" = 0 ] && [ "$enable_custom_clash_rules" = 0 ]; then
LOG_OUT "Error: OpenClash Can Not Start, Try Use Raw Config Restart Again..."
raw_config_start
else
LOG_OUT "Error: OpenClash Can Not Start, Try Use Backup Rules Start Again..."
ruby -ryaml -E UTF-8 -e "
begin
Value = YAML.load_file('$RAW_CONFIG_FILE');
Value_1 = YAML.load_file('$CONFIG_FILE');
if Value.has_key?('rule-providers') then
Value_1['rule-providers'] = Value.select {|x| 'rule-providers' == x}['rule-providers']
end;
if Value.has_key?('script') then
Value_1['script'] = Value.select {|x| 'script' == x}['script']
end;
if Value.has_key?('rules') then
Value_1['rules'] = Value.select {|x| 'rules' == x}['rules']
end;
File.open('$CONFIG_FILE','w') {|f| YAML.dump(Value_1, f)}
rescue Exception => e
puts '${LOGTIME} Error: Restore Backup Rules Error,【' + e.message + '】'
end
" 2>/dev/null >> $LOG_FILE
start_run_core
check_core_status
if ! pidof clash >/dev/null; then
LOG_OUT "Error: OpenClash Can Not Start, Try Use Raw Config Restart Again..."
raw_config_start
fi
fi
fi
}
#防火墙设置部分
ac_add()
{
if [ -z "$1" ]; then
return
fi
ipset add "$2" "$1" 2>/dev/null
[ -n "$3" ] && ipset add "$3" "$1" 2>/dev/null
}
firewall_rule_exclude()
{
local section="$1"
local name src src_port dest dest_port proto target enabled family
config_get "name" "$section" "name" ""
config_get "src" "$section" "src" ""
config_get "src_port" "$section" "src_port" ""
config_get "dest" "$section" "dest" ""
config_get "dest_port" "$section" "dest_port" ""
config_get "dest_ip" "$section" "dest_ip" ""
config_get "proto" "$section" "proto" ""
config_get "target" "$section" "target" ""
config_get "enabled" "$section" "enabled" ""
config_get "family" "$section" "family" ""
if [ a"$target" != aACCEPT ] || [ a"$enabled" == a0 ]; then
return
fi
local e_udp=false
local e_tcp=false
for p in $proto; do
if [ $p == tcp ]; then e_tcp=true; fi
if [ $p == udp ]; then e_udp=true; fi
if [ $p == all ]; then e_tcp=true; e_udp=true; fi
done
if [ -z "$proto" ]; then e_tcp=true; e_udp=true; fi
if ! $e_udp && ! $e_tcp ; then
return
fi
dest_port=$(echo $dest_port |sed "s/-/:/g" 2>/dev/null)
dest_ip=$(echo $dest_ip |sed "s/ /,/g" 2>/dev/null)
if [ -z "$family" ] || [ "$family" == "ipv4" ]; then
if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
for i in $dest_port; do
if $e_tcp ; then
iptables -t nat -I openclash_output -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
if [ -z "$dest_ip" ]; then
iptables -t nat -I openclash -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
else
iptables -t nat -I openclash -p tcp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
fi
fi
if $e_udp ; then
iptables -t mangle -I openclash_output -p udp --sport "$i" -j RETURN >/dev/null 2>&1
if [ -z "$dest_ip" ]; then
iptables -t mangle -I openclash -p udp --sport "$i" -j RETURN >/dev/null 2>&1
else
iptables -t mangle -I openclash -p udp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
fi
fi
done
elif [ "$en_mode_tun" -eq 1 ]; then
for i in $dest_port; do
if $e_tcp ; then
iptables -t mangle -I openclash_output -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
if [ -z "$dest_ip" ]; then
iptables -t mangle -I openclash -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
else
iptables -t mangle -I openclash -p tcp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
fi
fi
if $e_udp ; then
iptables -t mangle -I openclash_output -p udp --sport "$i" -j RETURN >/dev/null 2>&1
if [ -z "$dest_ip" ]; then
iptables -t mangle -I openclash -p udp --sport "$i" -j RETURN >/dev/null 2>&1
else
iptables -t mangle -I openclash -p udp -s "$dest_ip" --sport "$i" -j RETURN >/dev/null 2>&1
fi
fi
done
fi
fi
if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
if [ -z "$family" ] || [ "$family" == "ipv6" ]; then
for i in $dest_port; do
if $e_tcp ; then
if [ -z "$dest_ip" ]; then
ip6tables -t mangle -I openclash -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
else
ip6tables -t mangle -I openclash -s "$dest_ip" -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
fi
ip6tables -t mangle -I openclash_output -p tcp --sport "$i" -j RETURN >/dev/null 2>&1
fi
if $e_udp ; then
if [ -z "$dest_ip" ]; then
ip6tables -t mangle -I openclash -p udp --sport "$i" -j RETURN >/dev/null 2>&1
else
ip6tables -t mangle -I openclash -s "$dest_ip" -p udp --sport "$i" -j RETURN >/dev/null 2>&1
fi
ip6tables -t mangle -I openclash_output -p udp --sport "$i" -j RETURN >/dev/null 2>&1
fi
done
fi
fi
}
firewall_redirect_exclude()
{
local section="$1"
local src_dport dest_port dest_ip proto enabled
config_get "src_dport" "$section" "src_dport" ""
config_get "dest_port" "$section" "dest_port" ""
config_get "dest_ip" "$section" "dest_ip" ""
config_get "proto" "$section" "proto" ""
config_get "enabled" "$section" "enabled" ""
if [ -z "$src_dport" ] || [ a"$enabled" == a0 ]; then
return
fi
local e_udp=false
local e_tcp=false
for p in $proto; do
if [ $p == tcp ]; then e_tcp=true; fi
if [ $p == udp ]; then e_udp=true; fi
if [ $p == all ]; then e_tcp=true; e_udp=true; fi
done
if [ -z "$proto" ]; then e_tcp=true; e_udp=true; fi
if ! $e_udp && ! $e_tcp ; then
return
fi
if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
iptables -t nat -I openclash_output -p tcp --sport "$src_dport" -j RETURN >/dev/null 2>&1
iptables -t mangle -I openclash_output -p udp --sport "$src_dport" -j RETURN >/dev/null 2>&1
iptables -t mangle -I openclash -p udp --dport "$src_dport" -j RETURN >/dev/null 2>&1
elif [ "$en_mode_tun" -eq 1 ]; then
iptables -t mangle -I openclash_output -p tcp --sport "$src_dport" -j RETURN >/dev/null 2>&1
iptables -t mangle -I openclash_output -p udp --sport "$src_dport" -j RETURN >/dev/null 2>&1
iptables -t mangle -I openclash -p tcp --dport "$src_dport" -j RETURN >/dev/null 2>&1
iptables -t mangle -I openclash -p udp --dport "$src_dport" -j RETURN >/dev/null 2>&1
if $e_tcp ; then
iptables -t mangle -I openclash -p tcp -s "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
fi
if $e_udp ; then
iptables -t mangle -I openclash -p udp -s "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
fi
fi
if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
if $e_tcp ; then
ip6tables -t mangle -I openclash -p tcp --dport "$src_dport" -j RETURN >/dev/null 2>&1
ip6tables -t mangle -I openclash -p tcp -s "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
ip6tables -t mangle -I openclash_output -p tcp --sport "$src_dport" -j RETURN >/dev/null 2>&1
ip6tables -t mangle -I openclash_output -p tcp -s "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
fi
if $e_udp ; then
ip6tables -t mangle -I openclash -p udp --dport "$src_dport" -j RETURN >/dev/null 2>&1
ip6tables -t mangle -I openclash -p udp -s "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
ip6tables -t mangle -I openclash_output -p udp -s "$dest_ip" --sport "$dest_port" -j RETURN >/dev/null 2>&1
ip6tables -t mangle -I openclash_output -p udp --sport "$src_dport" -j RETURN >/dev/null 2>&1
fi
fi
}
set_firewall()
{
if [ -z "$(uci -q get firewall.openclash)" ] || [ -z "$(uci -q get ucitrack.@openclash[-1].init)" ]; then
uci -q delete ucitrack.@openclash[-1]
uci -q add ucitrack openclash
uci -q set ucitrack.@openclash[-1].init=openclash
uci -q commit ucitrack
uci -q delete firewall.openclash
uci -q set firewall.openclash=include
uci -q set firewall.openclash.type=script
uci -q set firewall.openclash.path=/var/etc/openclash.include
uci -q set firewall.openclash.reload=1
fi
mkdir -p /var/etc
cat > "/var/etc/openclash.include" <<-EOF
/etc/init.d/openclash reload >/dev/null 2>&1
EOF
if [ "$china_ip_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
ipset -! flush china_ip_route 2>/dev/null
ipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null
fi
if [ "$enable_redirect_dns" -eq 1 ] && [ -z "$(iptables -t nat -nL PREROUTING --line-number |grep 'OpenClash DNS Hijack')"]; then
DNSPORT=$(uci -q get dhcp.@dnsmasq[0].port)
if [ -z "$DNSPORT" ]; then
DNSPORT=$(netstat -nlp |grep -E '127.0.0.1:.*dnsmasq' |awk -F '127.0.0.1:' '{print $2}' |awk '{print $1}' |head -1 || echo "$dns_port")
fi
iptables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack"
iptables -t nat -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack"
fi
#Bypass Gateway Compatible
if [ "$bypass_gateway_compatible" -eq 1 ]; then
iptables -t nat -I POSTROUTING -m addrtype ! --src-type LOCAL -m owner ! --uid-owner 65534 -m comment --comment "OpenClash Bypass Gateway Compatible" -j MASQUERADE
iptables -t nat -I POSTROUTING -m mark --mark "$PROXY_FWMARK" -m comment --comment "OpenClash Bypass Gateway Compatible" -j ACCEPT
fi
#lan_ac
if [ "$operation_mode" = "redir-host" ] && [ "$en_mode" = "redir-host" ]; then
if [ "$lan_ac_mode" = "0" ]; then
if [ -n "$(uci -q get openclash.config.lan_ac_black_ips)" ]; then
ipset create lan_ac_black_ips hash:net
ipset create lan_ac_black_ipv6s hash:net family inet6
config_load "openclash"
config_list_foreach "config" "lan_ac_black_ips" ac_add "lan_ac_black_ips" "lan_ac_black_ipv6s"
fi
if [ -n "$(uci -q get openclash.config.lan_ac_black_macs)" ]; then
ipset create lan_ac_black_macs hash:mac
config_load "openclash"
config_list_foreach "config" "lan_ac_black_macs" ac_add "lan_ac_black_macs"
fi
elif [ "$lan_ac_mode" = "1" ]; then
if [ -n "$(uci -q get openclash.config.lan_ac_white_ips)" ]; then
ipset create lan_ac_white_ips hash:net
ipset create lan_ac_white_ipv6s hash:net family inet6
config_load "openclash"
config_list_foreach "config" "lan_ac_white_ips" ac_add "lan_ac_white_ips" "lan_ac_white_ipv6s"
fi
if [ -n "$(uci -q get openclash.config.lan_ac_white_macs)" ]; then
ipset create lan_ac_white_macs hash:mac
config_load "openclash"
config_list_foreach "config" "lan_ac_white_macs" ac_add "lan_ac_white_macs"
fi
fi
fi
#wan ac
if [ -n "$(uci -q get openclash.config.wan_ac_black_ips)" ]; then
ipset create wan_ac_black_ips hash:net
ipset create wan_ac_black_ipv6s hash:net family inet6
config_load "openclash"
config_list_foreach "config" "wan_ac_black_ips" ac_add "wan_ac_black_ips" "wan_ac_black_ipv6s"
fi
#local
ipset create localnetwork hash:net
ipset add localnetwork 0.0.0.0/8
ipset add localnetwork 127.0.0.0/8
ipset add localnetwork 10.0.0.0/8
ipset add localnetwork 169.254.0.0/16
ipset add localnetwork 192.168.0.0/16
ipset add localnetwork 224.0.0.0/4
ipset add localnetwork 240.0.0.0/4
ipset add localnetwork 172.16.0.0/12
ipset add localnetwork 100.64.0.0/10
if [ -n "$lan_ip_cidrs" ]; then
for lan_ip_cidr in $lan_ip_cidrs; do
ipset add localnetwork "$lan_ip_cidr" 2>/dev/null
done
fi
if [ -n "$wan_ip4s" ]; then
for wan_ip4 in $wan_ip4s; do
ipset add localnetwork "$wan_ip4" 2>/dev/null
done
fi
#common ports
if [ "$common_ports" = "1" ]; then
common_port="21 22 23 53 80 123 143 194 443 465 587 853 993 995 998 2052 2053 2082 2083 2086 2095 2096 5222 5228 5229 5230 8080 8443 8880 8888 8889"
ipset create common_ports bitmap:port range 0-65535
for i in $common_port; do
ipset add common_ports $i
done
fi
if [ -z "$en_mode_tun" ] || [ "$en_mode_tun" -eq 2 ]; then
#tcp
iptables -t nat -N openclash
iptables -t nat -F openclash
iptables -t nat -A openclash -m set --match-set localnetwork dst -j RETURN
iptables -t nat -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
iptables -t nat -A openclash -m set --match-set lan_ac_black_ips src -j RETURN >/dev/null 2>&1
iptables -t nat -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
iptables -t nat -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
iptables -t nat -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN >/dev/null 2>&1
if [ "$en_mode" = "redir-host" ]; then
iptables -t nat -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
if [ "$china_ip_route" = "1" ]; then
iptables -t nat -A openclash -m set --match-set china_ip_route dst -j RETURN >/dev/null 2>&1
fi
fi
iptables -t nat -A openclash -p tcp -j REDIRECT --to-ports "$proxy_port"
iptables -t nat -A PREROUTING -p tcp -j openclash
if [ -z "$en_mode_tun" ]; then
#Google dns
iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 8.8.8.8 --dport 53 -j REDIRECT --to-ports "$proxy_port"
iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 8.8.4.4 --dport 53 -j REDIRECT --to-ports "$proxy_port"
#udp
if [ "$enable_udp_proxy" -eq 1 ]; then
modprobe xt_TPROXY >/dev/null 2>&1
ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE"
iptables -t mangle -N openclash
iptables -t mangle -F openclash
iptables -t mangle -A openclash -m set --match-set localnetwork dst -j RETURN
iptables -t mangle -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set --match-set lan_ac_black_ips src -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
if [ "$en_mode" = "redir-host" ]; then
iptables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
if [ "$china_ip_route" = "1" ]; then
iptables -t mangle -A openclash -m set --match-set china_ip_route dst -j RETURN >/dev/null 2>&1
fi
fi
iptables -t mangle -A openclash -p udp --dport 53 -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -p udp -j TPROXY --on-port "$proxy_port" --tproxy-mark "$PROXY_FWMARK"
iptables -t mangle -A PREROUTING -p udp -j openclash
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT >/dev/null 2>&1
fi
elif [ "$en_mode" = "fake-ip" ]; then
modprobe xt_TPROXY >/dev/null 2>&1
ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
ip route add local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE"
iptables -t mangle -N openclash
iptables -t mangle -F openclash
iptables -t mangle -A openclash -p udp -d 198.18.0.0/16 -j TPROXY --on-port "$proxy_port" --tproxy-mark "$PROXY_FWMARK"
iptables -t mangle -A PREROUTING -p udp -j openclash
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
iptables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT >/dev/null 2>&1
fi
fi
fi
if [ -z "$_koolshare" ]; then
iptables -t nat -N openclash_output
iptables -t nat -F openclash_output
iptables -t nat -A openclash_output -m set --match-set localnetwork dst -j RETURN
if [ "$en_mode" = "fake-ip" ]; then
if [ "$intranet_allowed" -eq 1 ]; then
iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -p tcp -d 198.18.0.0/16 -j DNAT --to-destination "$lan_ip:$proxy_port"
else
iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$proxy_port"
fi
fi
iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
if [ "$en_mode" = "redir-host" ]; then
iptables -t nat -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
if [ "$china_ip_route" = "1" ]; then
iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip_route dst -j RETURN >/dev/null 2>&1
fi
fi
if [ "$intranet_allowed" -eq 1 ]; then
iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -p tcp -j DNAT --to-destination "$lan_ip:$proxy_port"
else
iptables -t nat -A openclash_output -m owner ! --uid-owner 65534 -p tcp -j REDIRECT --to-ports "$proxy_port"
fi
else
if [ "$en_mode" = "fake-ip" ]; then
iptables -t nat -N openclash_output
iptables -t nat -F openclash_output
if [ "$enable_redirect_dns" -eq 1 ] && [ -z "$(iptables -t nat -nL OUTPUT --line-number |grep 'OpenClash DNS Hijack')"]; then
iptables -t nat -I OUTPUT -p udp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack"
iptables -t nat -I OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack"
fi
iptables -t nat -A openclash_output -m set --match-set localnetwork dst -j RETURN
if [ "$intranet_allowed" -eq 1 ]; then
iptables -t nat -A openclash_output -p tcp -d 198.18.0.0/16 -j DNAT --to-destination "$lan_ip:$proxy_port"
else
iptables -t nat -A openclash_output -p tcp -d 198.18.0.0/16 -j REDIRECT --to-ports "$proxy_port"
fi
fi
fi
iptables -t nat -A OUTPUT -j openclash_output >/dev/null 2>&1
fi
if [ -n "$en_mode_tun" ]; then
#TUN模式
#启动TUN
TUN_WAIT=0
ip link set utun up
while ( [ -n "$(pidof clash)" ] && [ -z "$(ip route list |grep utun)" ] && [ "$TUN_WAIT" -le 3 ] )
do
ip link set utun up
let TUN_WAIT++
sleep 2
done
ip route replace default dev utun table "$PROXY_ROUTE_TABLE"
ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
#设置防火墙
if [ "$en_mode" = "fake-ip" ]; then
iptables -t mangle -N openclash_output
iptables -t mangle -F openclash_output
iptables -t mangle -A openclash_output -m set --match-set localnetwork dst -j RETURN
if [ "$en_mode_tun" -eq 1 ]; then
if [ -z "$_koolshare" ]; then
iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -d 198.18.0.0/16 -j MARK --set-mark "$PROXY_FWMARK"
iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -p tcp -j MARK --set-mark "$PROXY_FWMARK"
else
iptables -t mangle -A openclash_output -d 198.18.0.0/16 -j MARK --set-mark "$PROXY_FWMARK"
fi
elif [ -z "$_koolshare" ]; then
iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -p udp -d 198.18.0.0/16 -j MARK --set-mark "$PROXY_FWMARK"
fi
iptables -t mangle -A OUTPUT -j openclash_output
elif [ -z "$_koolshare" ] && [ "$en_mode" = "redir-host" ] && [ "$en_mode_tun" -eq 1 ]; then
iptables -t mangle -N openclash_output
iptables -t mangle -F openclash_output
iptables -t mangle -A openclash_output -m set --match-set localnetwork dst -j RETURN
iptables -t mangle -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
if [ "$china_ip_route" = "1" ]; then
iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip_route dst -j RETURN >/dev/null 2>&1
fi
iptables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -p tcp -j MARK --set-mark "$PROXY_FWMARK"
iptables -t mangle -A OUTPUT -j openclash_output
fi
iptables -t mangle -N openclash
iptables -t mangle -F openclash
iptables -t mangle -N openclash_dns_hijack
iptables -t mangle -F openclash_dns_hijack
#其他流量
iptables -t mangle -A openclash -i utun -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set --match-set localnetwork dst -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set --match-set lan_ac_black_ips src -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_ips src -j RETURN >/dev/null 2>&1
iptables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
if [ "$en_mode" = "redir-host" ]; then
iptables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
if [ "$china_ip_route" = "1" ]; then
iptables -t mangle -A openclash -m set --match-set china_ip_route dst -j RETURN >/dev/null 2>&1
fi
fi
iptables -t mangle -A openclash -j MARK --set-mark "$PROXY_FWMARK"
if [ "$en_mode_tun" -eq 1 ]; then
iptables -t mangle -I PREROUTING -j openclash
iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 8.8.8.8 --dport 53 -j ACCEPT
iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 8.8.4.4 --dport 53 -j ACCEPT
else
iptables -t mangle -I PREROUTING -p tcp --dport 53 -j openclash_dns_hijack
iptables -t mangle -A openclash_dns_hijack -m comment --comment "OpenClash Google DNS Hijack" -d 8.8.8.8 -j MARK --set-mark "$PROXY_FWMARK"
iptables -t mangle -A openclash_dns_hijack -m comment --comment "OpenClash Google DNS Hijack" -d 8.8.4.4 -j MARK --set-mark "$PROXY_FWMARK"
iptables -t mangle -I PREROUTING -p udp -j openclash
iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp --dport 53 -d 8.8.8.8 -j ACCEPT
iptables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp --dport 53 -d 8.8.4.4 -j ACCEPT
fi
#snat routerself for tun while bindaddress enable
if [ "$en_mode_tun" -eq 1 ] && [ "$intranet_allowed" -eq 1 ]; then
if [ -z "$_koolshare" ]; then
iptables -t nat -N openclash_post
iptables -t nat -F openclash_post
iptables -t nat -A openclash_post -m owner ! --uid-owner 65534 -i lo -d 127.0.0.1 -j SNAT --to-source "$lan_ip"
iptables -t nat -I POSTROUTING -j openclash_post
elif [ "$en_mode" = "fake-ip" ]; then
iptables -t nat -N openclash_post
iptables -t nat -F openclash_post
iptables -t nat -A openclash_post -i lo -d 127.0.0.1 -j SNAT --to-source "$lan_ip"
iptables -t nat -I POSTROUTING -j openclash_post
fi
fi
#TUN FORWORD
iptables -I FORWARD -m comment --comment "OpenClash TUN Forward" -o utun -j ACCEPT
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
iptables -I FORWARD -p udp --dport 443 -o utun -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip_route dst -j REJECT >/dev/null 2>&1
fi
fi
#ipv6
if [ "$ipv6_enable" -eq 1 ] && [ -n "$(ip6tables -t mangle -L 2>&1 | grep -o 'Chain')" ]; then
if [ "$enable_redirect_dns" -eq 1 ] && [ -z "$(ip6tables -t nat -nL PREROUTING --line-number |grep 'dns_hijack')"]; then
ip6tables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack"
ip6tables -t nat -I PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports "$DNSPORT" -m comment --comment "OpenClash DNS Hijack"
fi
if [ "$china_ip6_route" = "1" ] || [ "$disable_udp_quic" = "1" ]; then
ipset -! flush china_ip6_route 2>/dev/null
ipset -! restore </etc/openclash/china_ip6_route.ipset 2>/dev/null
fi
#local
ipset create localnetwork6 hash:net family inet6
ipset add localnetwork6 ::/128
ipset add localnetwork6 ::1/128
ipset add localnetwork6 ::ffff:0:0/96
ipset add localnetwork6 ::ffff:0:0:0/96
ipset add localnetwork6 64:ff9b::/96
ipset add localnetwork6 100::/64
ipset add localnetwork6 2001::/32
ipset add localnetwork6 2001:20::/28
ipset add localnetwork6 2001:db8::/32
ipset add localnetwork6 2002::/16
ipset add localnetwork6 fc00::/7
ipset add localnetwork6 fe80::/10
ipset add localnetwork6 ff00::/8
if [ -n "$wan_ip6s" ]; then
for wan_ip6 in $wan_ip6s; do
ipset add localnetwork6 "$wan_ip6"
done
fi
modprobe xt_TPROXY >/dev/null 2>&1
ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
ip -6 route add local ::/0 dev lo table "$PROXY_ROUTE_TABLE"
#Google dns
ip6tables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 2001:4860:4860::8888 --dport 53 -j ACCEPT
ip6tables -t nat -I PREROUTING -m comment --comment "OpenClash Google DNS Hijack" -p tcp -d 2001:4860:4860::8844 --dport 53 -j ACCEPT
ip6tables -t mangle -N openclash
ip6tables -t mangle -F openclash
ip6tables -t mangle -A openclash -m set --match-set localnetwork6 dst -j RETURN
ip6tables -t mangle -A openclash -m set --match-set wan_ac_black_ipv6s dst -j RETURN >/dev/null 2>&1
if [ "$en_mode" == "redir-host" ]; then
ip6tables -t mangle -A openclash -m set --match-set lan_ac_black_macs src -j RETURN >/dev/null 2>&1
ip6tables -t mangle -A openclash -m set --match-set lan_ac_black_ipv6s src -j RETURN >/dev/null 2>&1
ip6tables -t mangle -A openclash -m set ! --match-set lan_ac_white_ipv6s src -j RETURN >/dev/null 2>&1
ip6tables -t mangle -A openclash -m set ! --match-set lan_ac_white_macs src -j RETURN >/dev/null 2>&1
ip6tables -t mangle -A openclash -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
fi
if [ "$china_ip6_route" = "1" ]; then
ip6tables -t mangle -A openclash -m set --match-set china_ip6_route dst -j RETURN >/dev/null 2>&1
fi
ip6tables -t mangle -A openclash -p tcp -m comment --comment "OpenClash TCP Mark" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
ip6tables -t mangle -A PREROUTING -j openclash
if [ -z "$_koolshare" ]; then
ip6tables -t mangle -N openclash_output
ip6tables -t mangle -F openclash_output
ip6tables -t mangle -A openclash_output -m set --match-set localnetwork6 dst -j RETURN
ip6tables -t mangle -A openclash_output -m set --match-set wan_ac_black_ips dst -j RETURN >/dev/null 2>&1
ip6tables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set ! --match-set common_ports dst -j RETURN >/dev/null 2>&1
if [ "$china_ip6_route" = "1" ]; then
ip6tables -t mangle -A openclash_output -m owner ! --uid-owner 65534 -m set --match-set china_ip6_route dst -j RETURN >/dev/null 2>&1
fi
ip6tables -t mangle -A openclash_output -p tcp -m owner ! --uid-owner 65534 -j MARK --set-xmark "$PROXY_FWMARK"
ip6tables -t mangle -A OUTPUT -j openclash_output
fi
#udp
if [ "$enable_udp_proxy" -eq 1 ] || [ -n "$en_mode_tun" ]; then
ip6tables -t mangle -A openclash_output -p udp -m owner ! --uid-owner 65534 -j MARK --set-xmark "$PROXY_FWMARK"
ip6tables -t mangle -A openclash -p udp -m comment --comment "OpenClash" -j TPROXY --on-port "$tproxy_port" --tproxy-mark "$PROXY_FWMARK"
fi
#quic
if [ "$disable_udp_quic" -eq 1 ]; then
ip6tables -I INPUT -p udp --dport 443 -m comment --comment "OpenClash QUIC REJECT" -m set ! --match-set china_ip6_route dst -j REJECT >/dev/null 2>&1
fi
if [ "$bypass_gateway_compatible" -eq 1 ]; then
ip6tables -t nat -I POSTROUTING -m addrtype ! --src-type LOCAL -m owner ! --uid-owner 65534 -m comment --comment "OpenClash Bypass Gateway Compatible" -j MASQUERADE
ip6tables -t nat -I POSTROUTING -m mark --mark "$PROXY_FWMARK" -m comment --comment "OpenClash Bypass Gateway Compatible" -j ACCEPT
fi
fi 2>/dev/null
#端口转发
config_load "firewall"
config_foreach firewall_redirect_exclude "redirect"
config_foreach firewall_rule_exclude "rule"
}
revert_firewall()
{
rm -rf /var/etc/openclash.include
ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
ip route del local 0.0.0.0/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
ip -6 route del local ::/0 dev lo table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
#TUN
ip route del default dev utun table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" >/dev/null 2>&1
ip link set dev utun down >/dev/null 2>&1
ip tuntap del utun mode tun >/dev/null 2>&1
for ipt in "iptables -nvL INPUT" "iptables -nvL FORWARD" "iptables -nvL POSTROUTING -t nat" "iptables -nvL OUTPUT -t nat" "iptables -nvL OUTPUT -t mangle" "iptables -nvL PREROUTING -t nat" "iptables -nvL PREROUTING -t mangle" "ip6tables -nvL PREROUTING -t mangle" "ip6tables -nvL OUTPUT -t mangle" "ip6tables -nvL PREROUTING -t nat" "ip6tables -nvL INPUT"; do
for comment in "openclash" "OpenClash"; do
local lines=$($ipt |sed 1,2d |sed -n "/${comment}/=" 2>/dev/null |sort -rn)
if [ -n "$lines" ]; then
for line in $lines; do
$(echo "$ipt" |awk -v OFS=" " '{print $1,$4,$5}' |sed 's/[ ]*$//g') -D $(echo "$ipt" |awk '{print $3}') $line
done
fi
done
done >/dev/null 2>&1
for chain in "openclash" "openclash_output" "openclash_post" "openclash_dns_hijack"; do
iptables -t nat -F $chain
iptables -t nat -X $chain
iptables -t mangle -F $chain
iptables -t mangle -X $chain
ip6tables -t mangle -F $chain
ip6tables -t mangle -X $chain
done >/dev/null 2>&1
ipset destroy localnetwork6 >/dev/null 2>&1
ipset destroy china_ip6_route >/dev/null 2>&1
ipset destroy lan_ac_white_ipv6s >/dev/null 2>&1
ipset destroy lan_ac_black_ipv6s >/dev/null 2>&1
ipset destroy wan_ac_black_ipv6s >/dev/null 2>&1
ipset destroy localnetwork >/dev/null 2>&1
ipset destroy china_ip_route >/dev/null 2>&1
ipset destroy lan_ac_white_ips >/dev/null 2>&1
ipset destroy lan_ac_black_ips >/dev/null 2>&1
ipset destroy lan_ac_white_macs >/dev/null 2>&1
ipset destroy lan_ac_black_macs >/dev/null 2>&1
ipset destroy wan_ac_black_ips >/dev/null 2>&1
ipset destroy common_ports >/dev/null 2>&1
}
get_config()
{
rule_source=$(uci -q get openclash.config.rule_source)
enable_custom_dns=$(uci -q get openclash.config.enable_custom_dns)
enable_custom_clash_rules=$(uci -q get openclash.config.enable_custom_clash_rules)
da_password=$(uci -q get openclash.config.dashboard_password)
cn_port=$(uci -q get openclash.config.cn_port)
proxy_port=$(uci -q get openclash.config.proxy_port)
tproxy_port=$(uci -q get openclash.config.tproxy_port || echo 7895)
proxy_mode=$(uci -q get openclash.config.proxy_mode)
ipv6_enable=$(uci -q get openclash.config.ipv6_enable)
ipv6_dns=$(uci -q get openclash.config.ipv6_dns || echo 0)
http_port=$(uci -q get openclash.config.http_port)
socks_port=$(uci -q get openclash.config.socks_port)
enable_redirect_dns=$(uci -q get openclash.config.enable_redirect_dns)
lan_ip=$(uci -q get network.lan.ipaddr |awk -F '/' '{print $1}' 2>/dev/null || ip addr show 2>/dev/null | grep -w 'inet' | grep 'global' | grep 'brd' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1)
lan_ip_cidrs=$(ip route | grep "/" | awk '{print $1}' | grep -vE "^198.18" 2>/dev/null)
wan_ip4s=$(ifconfig | grep 'inet addr' | awk '{print $2}' | cut -d: -f2 | grep -vE "(^198.18|^192.168|^127.0)" 2>/dev/null)
wan_ip6s=$(ifconfig | grep 'inet6 addr' | awk '{print $3}' 2>/dev/null)
disable_masq_cache=$(uci -q get openclash.config.disable_masq_cache)
log_level=$(uci -q get openclash.config.log_level)
intranet_allowed=$(uci -q get openclash.config.intranet_allowed)
enable_udp_proxy=$(uci -q get openclash.config.enable_udp_proxy || echo 1)
disable_udp_quic=$(uci -q get openclash.config.disable_udp_quic)
operation_mode=$(uci -q get openclash.config.operation_mode)
lan_ac_mode=$(uci -q get openclash.config.lan_ac_mode)
enable_rule_proxy=$(uci -q get openclash.config.enable_rule_proxy)
stack_type=$(uci -q get openclash.config.stack_type)
china_ip_route=$(uci -q get openclash.config.china_ip_route)
china_ip6_route=$(uci -q get openclash.config.china_ip6_route)
small_flash_memory=$(uci -q get openclash.config.small_flash_memory)
mixed_port=$(uci -q get openclash.config.mixed_port)
interface_name=$(uci -q get openclash.config.interface_name)
common_ports=$(uci -q get openclash.config.common_ports)
dns_port=$(uci -q get openclash.config.dns_port)
tolerance=$(uci -q get openclash.config.tolerance)
custom_fallback_filter=$(uci -q get openclash.config.custom_fallback_filter)
stream_domains_prefetch=$(uci -q get openclash.config.stream_domains_prefetch || echo 0)
append_wan_dns=$(uci -q get openclash.config.append_wan_dns || echo 1)
store_fakeip=$(uci -q get openclash.config.store_fakeip || echo 1)
dns_remote=$(uci -q get openclash.config.dns_remote || echo 1)
bypass_gateway_compatible=$(uci -q get openclash.config.bypass_gateway_compatible || echo 0)
core_version=$(uci -q get openclash.config.core_version || echo 0)
github_address_mod=$(uci -q get openclash.config.github_address_mod || echo 0)
_koolshare=$(cat /usr/lib/os-release 2>/dev/null |grep OPENWRT_RELEASE 2>/dev/null |grep -i koolshare 2>/dev/null)
[ -z "$dns_port" ] && dns_port=7874 && uci -q set openclash.config.dns_port=7874
[ "$ipv6_enable" -eq 1 ] && [ "$intranet_allowed" -eq 1 ] && intranet_allowed=0 && uci -q set openclash.config.intranet_allowed=0
uci -q set openclash.config.restricted_mode=0 && uci -q commit openclash
}
start()
{
enable=$(uci -q get openclash.config.enable)
[ "$enable" != "1" ] && LOG_OUT "Warning: OpenClash Now Disabled, Need Start From Luci Page, Exit..." && SLOG_CLEAN && del_lock && exit 0
LOG_OUT "OpenClash Start Running..."
config_choose
do_run_mode
LOG_OUT "Step 1: Get The Configuration..."
get_config
LOG_OUT "Step 2: Check The Components..."
#检查文件是否存在
do_run_file "$RAW_CONFIG_FILE" "$BACKUP_FILE" "$en_mode"
#快速启动判断
check_run_quick
if ! $quick_start; then
LOG_OUT "Step 3: Modify The Config File..."
config_check
config_load "openclash"
config_foreach yml_auth_get "authentication"
yml_auth_custom "$CONFIG_FILE"
yml_dns_custom "$enable_custom_dns" "$CONFIG_FILE" "$append_wan_dns" "$ipv6_dns"
/usr/share/openclash/yml_change.sh 2>/dev/null "$LOGTIME" "$en_mode" "$enable_custom_dns" "$da_password" "$cn_port" "$proxy_port" "$CONFIG_FILE" "$ipv6_enable" "$http_port" "$socks_port" "$lan_ip" "$log_level" "$proxy_mode" "$intranet_allowed" "$en_mode_tun" "$stack_type" "$dns_port" "$core_type" "$mixed_port" "$tproxy_port" "$ipv6_dns" "$store_fakeip" "$stream_domains_prefetch" "$dns_remote"
/usr/share/openclash/yml_rules_change.sh 2>/dev/null "$LOGTIME" "$rule_source" "$enable_custom_clash_rules" "$CONFIG_FILE" "$enable_rule_proxy" "$CONFIG_NAME"
yml_custom_rule_provider
yml_game_custom
yml_provider_path "$CONFIG_FILE" "proxy-providers" "proxy_provider" "$github_address_mod"
yml_provider_path "$CONFIG_FILE" "rule-providers" "rule_provider" "$github_address_mod"
yml_vmess_compatible "$CONFIG_FILE" "proxies"
yml_dns_check "$CONFIG_FILE" "$FALLBACK_FILTER_FILE"
yml_tolerance_set "$CONFIG_FILE" "$tolerance"
fi
LOG_OUT "Step 4: Start Running The Clash Core..."
start_run_core
LOG_OUT "Step 5: Check The Core Status..."
check_core_status
#检测proxy_provider配置文件状态
LOG_OUT "Step 6: Wait For The File Downloading..."
yml_provider_check "$CONFIG_FILE" "proxy-providers" "proxies"
yml_provider_check "$CONFIG_FILE" "rule-providers" "payload"
try_restore_start
LOG_OUT "Step 7: Set Control Panel..."
ln -s /usr/share/openclash/yacd /www/luci-static/openclash 2>/dev/null
LOG_OUT "Step 8: Set Firewall Rules..."
set_firewall
LOG_OUT "Step 9: Restart Dnsmasq..."
change_dns "$enable_redirect_dns" "$disable_masq_cache"
/etc/init.d/dnsmasq restart >/dev/null 2>&1
LOG_OUT "Step 10: Add Cron Rules, Start Daemons..."
add_cron
if [ -z "$(uci -q get dhcp.lan.dhcpv6)" ] && [ "$(uci -q get openclash.config.restricted_mode)" != "1" ]; then
LOG_OUT "OpenClash Start Successful!"
sleep 3
elif [ -n "$(uci -q get dhcp.lan.dhcpv6)" ] && [ "$ipv6_enable" -eq 0 ]; then
LOG_OUT "Warning: OpenClash Start Successful, Please Note That Network May Abnormal With IPv6's DHCP Server"
sleep 3
fi
if [ "$(uci -q get openclash.config.restricted_mode)" = "1" ]; then
LOG_OUT "Warning: OpenClash Start Successful With Raw Config File, Please Note That It's Restricted Mode Now"
sleep 3
fi
echo "OpenClash Already Start!"
write_run_quick
SLOG_CLEAN
rm -rf /tmp/yaml_*
}
stop()
{
enable=$(uci -q get openclash.config.enable)
LOG_OUT "OpenClash Stoping..."
LOG_OUT "Step 1: Backup The Current Groups State..."
/usr/share/openclash/openclash_history_get.sh 2>/dev/null
LOG_OUT "Step 2: Delete OpenClash Firewall Rules..."
revert_firewall
LOG_OUT "Step 3: Close The OpenClash Daemons..."
watchdog_pids=$(unify_ps_pids "openclash_watchdog.sh")
for watchdog_pid in $watchdog_pids; do
kill -9 "$watchdog_pid" >/dev/null 2>&1
done >/dev/null 2>&1
streaming_unlock_pids=$(unify_ps_pids "openclash_streaming_unlock.lua")
for streaming_unlock_pid in $streaming_unlock_pids; do
kill -9 "$streaming_unlock_pid" >/dev/null 2>&1
done >/dev/null 2>&1
LOG_OUT "Step 4: Close The Clash Core Process..."
if [ "$enable" != "1" ]; then
kill_clash
fi
LOG_OUT "Step 5: Restart Dnsmasq..."
dns_port=$(uci -q get openclash.config.dns_port)
redirect_dns=$(uci -q get openclash.config.redirect_dns)
masq_cache=$(uci -q get openclash.config.masq_cache)
default_resolvfile=$(uci -q get openclash.config.default_resolvfile)
revert_dns "$redirect_dns" "$masq_cache" "$dns_port" "$enable" "$default_resolvfile"
/etc/init.d/dnsmasq restart >/dev/null 2>&1
LOG_OUT "Step 6: Delete OpenClash Residue File..."
if [ "$enable" != "1" ]; then
rm -rf /www/luci-static/openclash >/dev/null 2>&1
rm -rf /tmp/clash_last_version >/dev/null 2>&1
rm -rf /tmp/Proxy_Group >/dev/null 2>&1
rm -rf /tmp/rules_name >/dev/null 2>&1
rm -rf /tmp/rule_providers_name >/dev/null 2>&1
rm -rf /tmp/openclash_fake_filter.list >/dev/null 2>&1
rm -rf /tmp/openclash_servers_fake_filter.conf >/dev/null 2>&1
rm -rf /tmp/openclash_last_version >/dev/null 2>&1
rm -rf /tmp/openclash_config.tmp >/dev/null 2>&1
rm -rf /tmp/openclash.change >/dev/null 2>&1
rm -rf /tmp/openclash_debug.log >/dev/null 2>&1
rm -rf /tmp/etc/openclash >/dev/null 2>&1
rm -rf /tmp/openclash_edit_file_name >/dev/null 2>&1
del_lock
LOG_OUT "OpenClash Already Stop!"
sleep 3
rm -rf $LOG_FILE
fi
del_cron
rm -rf /tmp/yaml_* >/dev/null 2>&1
rm -rf $START_LOG >/dev/null 2>&1
echo "OpenClash Already Stop!"
}
restart()
{
[ -f "$LOCK_FILE" ] && LOG_OUT "Warning: Multiple Restart Scripts Running, Exit..." && SLOG_CLEAN && exit 0
mkdir -p /tmp/lock
touch $LOCK_FILE
set_lock
stop
start
del_lock
}
reload()
{
if pidof clash >/dev/null; then
set_lock
revert_firewall 2>/dev/null
do_run_mode 2>/dev/null
get_config 2>/dev/null
set_firewall 2>/dev/null
/etc/init.d/dnsmasq restart >/dev/null 2>&1
LOG_OUT "Reload OpenClash Firewall Rules..."
SLOG_CLEAN
del_lock
fi
}
boot()
{
delay_start=$(uci -q get openclash.config.delay_start || echo 0)
enable=$(uci -q get openclash.config.enable)
if [ "$delay_start" -gt 0 ] && [ "$enable" == "1" ]; then
LOG_OUT "Enable Delay Start, OpenClash Will Start After【$delay_start】Secends..."
sleep "$delay_start"
fi
restart
}