Files
op-packages/luci-app-openclash/root/usr/share/openclash/yml_change.sh
T

829 lines
34 KiB
Bash
Executable File

#!/bin/sh
. /usr/share/openclash/ruby.sh
. /usr/share/openclash/log.sh
. /usr/share/openclash/uci.sh
. /lib/functions.sh
LOG_FILE="/tmp/openclash.log"
CONFIG_FILE="$5"
custom_fakeip_filter=$(uci_get_config "custom_fakeip_filter" || echo 0)
custom_name_policy=$(uci_get_config "custom_name_policy" || echo 0)
custom_proxy_server_policy=$(uci_get_config "custom_proxy_server_policy" || echo 0)
custom_host=$(uci_get_config "custom_host" || echo 0)
enable_custom_dns=$(uci_get_config "enable_custom_dns" || echo 0)
append_wan_dns=$(uci_get_config "append_wan_dns" || echo 0)
custom_fallback_filter=$(uci_get_config "custom_fallback_filter" || echo 0)
china_ip_route=$(uci_get_config "china_ip_route" || echo 0)
china_ip6_route=$(uci_get_config "china_ip6_route" || echo 0)
enable_redirect_dns=$(uci_get_config "enable_redirect_dns" || echo 1)
fake_ip_filter_mode=${34}
default_dashboard=$(uci_get_config "default_dashboard" || echo "metacubexd")
yacd_type=$(uci_get_config "yacd_type" || echo "Official")
dashboard_type=$(uci_get_config "dashboard_type" || echo "Official")
[ "$china_ip_route" -ne 0 ] && [ "$china_ip_route" -ne 1 ] && [ "$china_ip_route" -ne 2 ] && china_ip_route=0
[ "$china_ip6_route" -ne 0 ] && [ "$china_ip6_route" -ne 1 ] && [ "$china_ip6_route" -ne 2 ] && china_ip6_route=0
en_mode_tun=${11:-0}
if [ -z "${12}" ]; then
stack_type=${30:-"system"}
else
stack_type=${12}
fi
if [ "$1" = "fake-ip" ] && [ "$enable_redirect_dns" != "2" ]; then
TMP_FILTER_FILE="/tmp/yaml_openclash_fake_filter_include"
> "$TMP_FILTER_FILE"
process_pass_list() {
[ ! -f "$1" ] && return
awk -v mode="$fake_ip_filter_mode" '
!/^$/ && !/^#/ {
# 跳过IPv4和IPv6地址
if ($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\/[0-9]+)?$/ || $0 ~ /:/) {
next
}
if (mode == "blacklist") {
if ($0 ~ /^\+?\./ || $0 ~ /^\*\./) {
print $0
} else {
print "+."$0
}
} else if (mode == "rule") {
domain = $0
sub(/^[\+\*\.]+/, "", domain)
print "DOMAIN-SUFFIX," domain ",real-ip"
}
}
' "$1" >> "$TMP_FILTER_FILE" 2>/dev/null
}
if [ "$china_ip_route" != "0" ]; then
process_pass_list "/etc/openclash/custom/openclash_custom_chnroute_pass.list"
fi
if [ "$china_ip6_route" != "0" ]; then
process_pass_list "/etc/openclash/custom/openclash_custom_chnroute6_pass.list"
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
LOG_TIP "You have seted the authentication of SOCKS5/HTTP(S) proxy with【$username:$password】..."
echo " - $username:$password" >>/tmp/yaml_openclash_auth
fi
}
# 添加自定义DNS设置
yml_dns_custom()
{
if [ "$1" = 1 ] || [ "$3" = 1 ]; then
sys_dns_append "$3" "$4"
config_foreach yml_dns_get "dns_servers" "$2"
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")
pppoe_iface=$(/usr/share/openclash/openclash_get_network.lua "pppoe")
if [ -z "$dhcp_iface" ] && [ -z "$pppoe_iface" ]; then
if [ -n "$wan_dns" ]; then
for i in $wan_dns; do
echo " - \"$i\"" >>/tmp/yaml_config.namedns.yaml
done
fi
if [ -n "$wan6_dns" ] && [ "$2" = 1 ]; then
for i in $wan6_dns; do
echo " - \"[${i}]:53\"" >>/tmp/yaml_config.namedns.yaml
done
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
else
if [ -n "$dhcp_iface" ]; then
for i in $dhcp_iface; do
echo " - dhcp://\"$i\"" >>/tmp/yaml_config.namedns.yaml
done
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
fi
if [ -n "$pppoe_iface" ]; then
if [ -n "$wan_dns" ]; then
for i in $wan_dns; do
echo " - \"$i\"" >>/tmp/yaml_config.namedns.yaml
done
fi
if [ -n "$wan6_dns" ] && [ "$2" = 1 ]; then
for i in $wan6_dns; do
echo " - \"[${i}]:53\"" >>/tmp/yaml_config.namedns.yaml
done
fi
fi
fi
if [ -f "/tmp/yaml_config.namedns.yaml" ] && [ -z "$(grep "^ \{0,\}nameserver:$" /tmp/yaml_config.namedns.yaml 2>/dev/null)" ]; then
sed -i '1i\ nameserver:' "/tmp/yaml_config.namedns.yaml"
fi
fi
}
PROXY_GROUPS=$(ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
begin
Value = YAML.load_file('$CONFIG_FILE')
File.open('/tmp/yaml_change_marshal', 'wb') { |f| Marshal.dump(Value, f) }
if Value.key?('proxy-groups') && Value['proxy-groups'].is_a?(Array)
Value['proxy-groups'].each { |x| puts x['name'] if x.key?('name') }
end
rescue Exception => e
YAML.LOG_ERROR('proxy-groups Get Failed,【%s】' % [e.message])
end
" 2>/dev/null)
set_disable_qtype()
{
if [ -z "$1" ]; then
return
fi
[ -z "$disable_qtype_param" ] && disable_qtype_param="disable-qtype-$1=true" || disable_qtype_param="$disable_qtype_param&disable-qtype-$1=true"
}
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 interface specific_group node_resolve direct_nameserver http3 skip_cert_verify ecs_subnet ecs_override disable_qtype_param disable_qtype disable_ipv4 disable_ipv6 disable_reuse
config_get_bool "enabled" "$section" "enabled" "1"
[ "$enabled" = "0" ] && return
config_get "ip" "$section" "ip" ""
[ -z "$ip" ] && return
config_get "port" "$section" "port" ""
config_get "type" "$section" "type" ""
config_get "group" "$section" "group" ""
config_get "interface" "$section" "interface" ""
config_get "specific_group" "$section" "specific_group" ""
config_get_bool "node_resolve" "$section" "node_resolve" "0"
config_get_bool "direct_nameserver" "$section" "direct_nameserver" "0"
config_get_bool "http3" "$section" "http3" "0"
config_get_bool "skip_cert_verify" "$section" "skip_cert_verify" "0"
config_get_bool "ecs_override" "$section" "ecs_override" "0"
config_get "ecs_subnet" "$section" "ecs_subnet" ""
config_get_bool "disable_ipv4" "$section" "disable_ipv4" "0"
config_get_bool "disable_ipv6" "$section" "disable_ipv6" "0"
config_get_bool "disable_reuse" "$section" "disable_reuse" "0"
config_list_foreach "$section" "disable_qtype" set_disable_qtype
if [[ "$ip" =~ "$regex" ]] || [ -n "$(echo "${ip}" | grep -Eo "${regex}")" ]; then
ip="[${ip}]"
fi
case "$type" in
"tcp") dns_type="tcp://" ;;
"tls") dns_type="tls://" ;;
"udp") dns_type="" ;;
"https") dns_type="https://" ;;
"quic") dns_type="quic://" ;;
*) dns_type="" ;;
esac
if [ -n "$port" ]; then
if [ "${ip%%/*}" != "${ip#*/}" ]; then
dns_address="${ip%%/*}:$port/${ip#*/}"
else
dns_address="$ip:$port"
fi
else
dns_address="$ip"
fi
if [ "$specific_group" != "Disable" ] && [ -n "$specific_group" ]; then
group_check=$(echo "$PROXY_GROUPS" | grep -F -w -m 1 "$specific_group")
[ -n "$group_check" ] && specific_group_param="$group_check" || specific_group_param=""
else
specific_group_param=""
fi
[ "$interface" != "Disable" ] && [ -n "$interface" ] && interface_param="$interface" || interface_param=""
[ "$http3" = "1" ] && http3_param="h3=true" || http3_param=""
[ "$skip_cert_verify" = "1" ] && skip_cert_verify_param="skip-cert-verify=true" || skip_cert_verify_param=""
[ -n "$ecs_subnet" ] && ecs_subnet_param="ecs=$ecs_subnet" || ecs_subnet_param=""
[ "$ecs_override" = "1" ] && [ -n "$ecs_subnet_param" ] && ecs_override_param="ecs-override=true" || ecs_override_param=""
[ "$disable_ipv4" = "1" ] && disable_ipv4_param="disable-ipv4=true" || disable_ipv4_param=""
[ "$disable_ipv6" = "1" ] && disable_ipv6_param="disable-ipv6=true" || disable_ipv6_param=""
[ "$disable_reuse" = "1" ] && disable_reuse_param="disable-reuse=true" || disable_reuse_param=""
params=""
append_param() {
if [ -n "$1" ]; then
[ -z "$params" ] && params="#" || params="$params&"
params="$params$1"
fi
}
append_param "$specific_group_param"
append_param "$interface_param"
append_param "$http3_param"
append_param "$skip_cert_verify_param"
append_param "$ecs_subnet_param"
append_param "$ecs_override_param"
append_param "$disable_ipv4_param"
append_param "$disable_ipv6_param"
append_param "$disable_qtype_param"
append_param "$disable_reuse_param"
full_dns_address="$dns_type$dns_address$params"
if [ "$node_resolve" = "1" ]; then
if ! grep -q "^ \{0,\}proxy-server-nameserver:$" /tmp/yaml_config.proxynamedns.yaml 2>/dev/null; then
echo " proxy-server-nameserver:" >/tmp/yaml_config.proxynamedns.yaml
fi
echo " - \"$full_dns_address\"" >>/tmp/yaml_config.proxynamedns.yaml
fi
if [ "$direct_nameserver" = "1" ]; then
if ! grep -q "^ \{0,\}direct-nameserver:$" /tmp/yaml_config.directnamedns.yaml 2>/dev/null; then
echo " direct-nameserver:" >/tmp/yaml_config.directnamedns.yaml
fi
echo " - \"$full_dns_address\"" >>/tmp/yaml_config.directnamedns.yaml
fi
case "$group" in
"nameserver")
if ! grep -q "^ \{0,\}nameserver:$" /tmp/yaml_config.namedns.yaml 2>/dev/null; then
echo " nameserver:" >/tmp/yaml_config.namedns.yaml
fi
echo " - \"$full_dns_address\"" >>/tmp/yaml_config.namedns.yaml
;;
"fallback")
if ! grep -q "^ \{0,\}fallback:$" /tmp/yaml_config.falldns.yaml 2>/dev/null; then
echo " fallback:" >/tmp/yaml_config.falldns.yaml
fi
echo " - \"$full_dns_address\"" >>/tmp/yaml_config.falldns.yaml
;;
"default")
if ! grep -q "^ \{0,\}default-nameserver:$" /tmp/yaml_config.defaultdns.yaml 2>/dev/null; then
echo " default-nameserver:" >/tmp/yaml_config.defaultdns.yaml
fi
echo " - \"$full_dns_address\"" >>/tmp/yaml_config.defaultdns.yaml
;;
esac
}
config_load "openclash"
config_foreach yml_auth_get "authentication"
yml_dns_custom "$enable_custom_dns" "$5" "$append_wan_dns" "${16}"
ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
def safe_load_yaml(file_path)
return nil unless File.exist?(file_path)
YAML.load_file(file_path)
rescue
nil
end
def merge_list_from_file(dns_hash, key, file_path)
return unless File.exist?(file_path)
lines = File.readlines(file_path).map { |l| l.gsub(/#.*$/, '').strip }.reject(&:empty?)
return if lines.empty?
(dns_hash[key] ||= []).unshift(*lines).uniq!
end
begin
config_file = '$5'
if File.exist?('/tmp/yaml_change_marshal')
begin
Value = Marshal.load(File.open('/tmp/yaml_change_marshal', 'rb') { |f| f.read })
rescue
Value = YAML.load_file(config_file)
end
else
Value = YAML.load_file(config_file)
end
rescue Exception => e
YAML.LOG_ERROR('Load File Failed,【%s】' % [e.message])
exit
end
begin
fake_ip_mode = '$1'
secret = '$2'
controller_port = '$3'
redir_port = '$4'
enable_ipv6 = '$6' == '1'
http_port = '$7'
socks_port = '$8'
log_level = '$9'
mode = '${10}'
en_mode_tun = '$en_mode_tun'
stack_type = '$stack_type'
dns_listen_port = '${13}'
mixed_port = '${14}'
tproxy_port = '${15}'
dns_ipv6 = '${16}' == '1'
store_fake_ip = '${17}' == '1'
enable_sniffer = '${18}' == '1'
geodata_mode = '${19}' == '1'
geodata_loader = '${20}'
append_sniffer_config = '${21}' == '1'
interface_name = '${22}'
tcp_concurrent = '${23}' == '1'
add_default_from_dns = '${25}' == '1'
sniffer_parse_pure_ip = '${26}' == '1'
find_process_mode = '${27}'
fake_ip_range = '${28}'
ipv6_mode = '${29}'
unified_delay = '${31}' == '1'
respect_rules = '${32}' == '1'
fake_ip_filter_mode = '${33}'
routing_mark_setting = '${34}'
quic_gso = '${35}' == '1'
cors_origin = '${36}'
geo_custom_url = '${37}'
geoip_custom_url = '${38}'
geosite_custom_url = '${39}'
geoasn_custom_url = '${40}'
lgbm_auto_update = '${41}' == '1'
lgbm_custom_url = '${42}'
lgbm_update_interval = '${43}'
smart_collect = '${44}' == '1'
smart_collect_size = '${45}'
fake_ip_range6 = '${46}'
fake_ip_range6_enable = '${47}' == '1'
global_ua = '${48}'
default_dashboard = '$default_dashboard'
yacd_type = '$yacd_type'
dashboard_type = '$dashboard_type'
enable_custom_dns = '$enable_custom_dns' == '1'
append_wan_dns = '$append_wan_dns' == '1'
custom_fakeip_filter = '$custom_fakeip_filter' == '1'
china_ip_route = '$china_ip_route' != '0'
china_ip6_route = '$china_ip6_route' != '0'
custom_name_policy = '$custom_name_policy' == '1'
custom_proxy_server_policy = '$custom_proxy_server_policy' == '1'
custom_host = '$custom_host' == '1'
enable_redirect_dns = '$enable_redirect_dns'
Value['dns'] ||= {}
threads = []
threads << Thread.new do
begin
Value['redir-port'] = redir_port.to_i
Value['tproxy-port'] = tproxy_port.to_i
Value['port'] = http_port.to_i
Value['socks-port'] = socks_port.to_i
Value['mixed-port'] = mixed_port.to_i
Value['mode'] = mode
Value['log-level'] = log_level if log_level != '0'
Value['allow-lan'] = true
Value['external-controller'] = '0.0.0.0:' + controller_port
Value['secret'] = secret
Value['bind-address'] = '*'
Value['global-ua'] = global_ua if global_ua != '0'
Value['external-ui'] = '/usr/share/openclash/ui'
Value['external-ui-name'] = default_dashboard
case default_dashboard
when 'dashboard'
if dashboard_type == 'Official'
Value['external-ui-url'] = 'https://codeload.github.com/ayanamist/clash-dashboard/zip/refs/heads/gh-pages'
else
Value['external-ui-url'] = 'https://codeload.github.com/MetaCubeX/Razord-meta/zip/refs/heads/gh-pages'
end
when 'yacd'
if yacd_type == 'Official'
Value['external-ui-url'] = 'https://codeload.github.com/haishanh/yacd/zip/refs/heads/gh-pages'
else
Value['external-ui-url'] = 'https://codeload.github.com/MetaCubeX/Yacd-meta/zip/refs/heads/gh-pages'
end
when 'metacubexd'
Value['external-ui-url'] = 'https://codeload.github.com/MetaCubeX/metacubexd/zip/refs/heads/gh-pages'
when 'zashboard'
Value['external-ui-url'] = 'https://codeload.github.com/Zephyruso/zashboard/zip/refs/heads/gh-pages-cdn-fonts'
end
if !Value.key?('keep-alive-interval') && !Value.key?('keep-alive-idle')
Value['keep-alive-interval'] = 15
Value['keep-alive-idle'] = 600
end
Value['ipv6'] = enable_ipv6
Value['interface-name'] = interface_name if interface_name != '0'
Value['geodata-mode'] = true if geodata_mode
Value['geodata-loader'] = geodata_loader if geodata_loader != '0'
Value['tcp-concurrent'] = true if tcp_concurrent
Value['unified-delay'] = true if unified_delay
Value['find-process-mode'] = find_process_mode if find_process_mode != '0'
(Value['experimental'] ||= {})['quic-go-disable-gso'] = true if quic_gso
if cors_origin != '0'
(Value['external-controller-cors'] ||= {})['allow-origins'] = [cors_origin]
Value['external-controller-cors']['allow-private-network'] = true
end
Value['lgbm-auto-update'] = true if lgbm_auto_update
if lgbm_auto_update
Value['lgbm-url'] = lgbm_custom_url.strip
Value['lgbm-update-interval'] = lgbm_update_interval.to_i
end
if smart_collect
(Value['profile'] ||= {})['smart-collector-size'] = smart_collect_size.to_f
end
Value['geox-url'] ||= {}
if geo_custom_url != '0'
Value['geox-url']['mmdb'] = geo_custom_url
end
if geoip_custom_url != '0'
Value['geox-url']['geoip'] = geoip_custom_url
end
if geosite_custom_url != '0'
Value['geox-url']['geosite'] = geosite_custom_url
end
if geoasn_custom_url != '0'
Value['geox-url']['asn'] = geoasn_custom_url
end
Value['dns']['enable'] = true
Value['dns']['ipv6'] = dns_ipv6
Value['ipv6'] = true if dns_ipv6
if fake_ip_mode == 'redir-host'
Value['dns']['enhanced-mode'] = 'redir-host'
Value['dns'].delete('fake-ip-range')
else
Value['dns']['enhanced-mode'] = 'fake-ip'
Value['dns']['fake-ip-range'] = fake_ip_range
if Value['dns']['ipv6'] and fake_ip_range6_enable
Value['dns']['fake-ip-range6'] = fake_ip_range6
end
end
Value['dns']['listen'] = '0.0.0.0:' + dns_listen_port
Value['dns']['respect-rules'] = respect_rules
if enable_sniffer
sniffer_config = {
'enable' => true, 'override-destination' => true,
'sniff' => {'QUIC' => {'ports' => [443]}, 'TLS' => {'ports' => [443, 8443]}, 'HTTP' => {'ports' => [80, '8080-8880'], 'override-destination' => true}},
'force-domain' => ['+.netflix.com', '+.nflxvideo.net', '+.amazonaws.com', '+.media.dssott.com'],
'skip-domain' => ['Mijia Cloud', 'dlg.io.mi.com', '+.oray.com', '+.sunlogin.net', '+.push.apple.com']
}
sniffer_config['force-dns-mapping'] = true if fake_ip_mode == 'redir-host'
sniffer_config['parse-pure-ip'] = true if sniffer_parse_pure_ip
Value['sniffer'] = sniffer_config
if append_sniffer_config && (custom_sniffer = safe_load_yaml('/etc/openclash/custom/openclash_custom_sniffer.yaml'))
Value['sniffer'].merge!(custom_sniffer['sniffer']) if custom_sniffer && custom_sniffer['sniffer']
end
else
Value['sniffer']['enable'] = false if Value.key?('sniffer')
end
if en_mode_tun != '0' || ['2', '3'].include?(ipv6_mode)
Value['tun'] = {
'enable' => true, 'stack' => stack_type, 'device' => 'utun',
'dns-hijack' => ['127.0.0.1:53'], 'endpoint-independent-nat' => true,
'auto-route' => false, 'auto-detect-interface' => false,
'auto-redirect' => false, 'strict-route' => false, 'disable-icmp-forwarding' => false
}
Value['tun'].delete('iproute2-table-index')
else
Value.delete('tun')
end
Value.delete('iptables')
(Value['profile'] ||= {})['store-selected'] = true
Value['profile']['store-fake-ip'] = true if store_fake_ip
Value.delete('ebpf')
if routing_mark_setting == '0'
Value['routing-mark'] = 6666
else
Value.delete('routing-mark')
end
Value.delete('auto-redir')
(Value['ntp'] ||= {})['enable'] = true
Value['ntp']['server'] = 'time.apple.com' if !Value['ntp'].key?('server')
Value['ntp']['port'] = 123 if !Value['ntp'].key?('port')
Value['ntp']['interval'] = 30 if !Value['ntp'].key?('interval')
Value['ntp']['write-to-system'] = true if !Value['ntp'].key?('write-to-system')
rescue Exception => e
YAML.LOG_ERROR('Set General Failed,【%s】' % [e.message])
end
end
threads << Thread.new do
begin
if enable_custom_dns || append_wan_dns
if (namedns_config = safe_load_yaml('/tmp/yaml_config.namedns.yaml')) && namedns_config['nameserver']
if enable_custom_dns
Value['dns']['nameserver'] = namedns_config['nameserver'].uniq
elsif append_wan_dns
(Value['dns']['nameserver'] ||= []).concat(namedns_config['nameserver']).uniq!
end
if enable_custom_dns && (falldns_config = safe_load_yaml('/tmp/yaml_config.falldns.yaml')) && falldns_config['fallback']
Value['dns']['fallback'] = falldns_config['fallback'].uniq
end
elsif enable_custom_dns
YAML.LOG_ERROR('Nameserver Option Must Be Setted, Stop Customing DNS Servers')
end
end
rescue Exception => e
YAML.LOG_ERROR('Set Custom DNS Failed,【%s】' % [e.message])
end
begin
if enable_custom_dns
if (defaultdns_config = safe_load_yaml('/tmp/yaml_config.defaultdns.yaml')) && defaultdns_config['default-nameserver']
Value['dns']['default-nameserver'] = defaultdns_config['default-nameserver'].uniq
end
end
if add_default_from_dns
reg = /^dhcp:\/\/|^system($|:\/\/)|([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/
servers_to_check = Value.dig('dns', 'nameserver').to_a | Value.dig('dns', 'fallback').to_a
non_domain_servers = servers_to_check.reject { |s| s.match?(reg) }
if non_domain_servers.any?
(Value['dns']['default-nameserver'] ||= []).concat(non_domain_servers).uniq!
end
end
rescue Exception => e
YAML.LOG_ERROR('Set default-nameserver Failed,【%s】' % [e.message])
end
begin
if '$custom_fallback_filter' == '1'
if !Value.dig('dns', 'fallback')
YAML.LOG_ERROR('Fallback-Filter Need fallback of DNS Been Setted, Ignore...')
elsif (filter_config = safe_load_yaml('/etc/openclash/custom/openclash_custom_fallback_filter.yaml'))
Value['dns']['fallback-filter'] = filter_config['fallback-filter']
else
YAML.LOG_ERROR('Unable To Parse Custom Fallback-Filter File, Ignore...')
end
end
rescue Exception => e
YAML.LOG_ERROR('Set fallback-filter Failed,【%s】' % [e.message])
end
end
# proxy-server-nameserver
threads << Thread.new do
begin
if enable_custom_dns
if (proxydns = safe_load_yaml('/tmp/yaml_config.proxynamedns.yaml')) && proxydns['proxy-server-nameserver']
(Value['dns']['proxy-server-nameserver'] ||= []).concat(proxydns['proxy-server-nameserver']).uniq!
end
end
rescue Exception => e
YAML.LOG_ERROR('Set proxy-server-nameserver Failed,【%s】' % [e.message])
end
end
# direct-nameserver
threads << Thread.new do
begin
if enable_custom_dns
if (directdns = safe_load_yaml('/tmp/yaml_config.directnamedns.yaml')) && directdns['direct-nameserver']
(Value['dns']['direct-nameserver'] ||= []).concat(directdns['direct-nameserver']).uniq!
end
end
rescue Exception => e
YAML.LOG_ERROR('Set direct-nameserver Failed,【%s】' % [e.message])
end
end
# nameserver-policy
threads << Thread.new do
begin
if custom_name_policy
if (policy = safe_load_yaml('/etc/openclash/custom/openclash_custom_domain_dns_policy.list'))
(Value['dns']['nameserver-policy'] ||= {}).merge!(policy)
end
end
rescue Exception => e
YAML.LOG_ERROR('Set Nameserver-Policy Failed,【%s】' % [e.message])
end
end
# proxy-server-nameserver-policy
threads << Thread.new do
begin
if custom_proxy_server_policy
if (policy = safe_load_yaml('/etc/openclash/custom/openclash_custom_proxy_server_dns_policy.list'))
(Value['dns']['proxy-server-nameserver-policy'] ||= {}).merge!(policy)
end
end
rescue Exception => e
YAML.LOG_ERROR('Set Proxy-Server-Nameserver-Policy Failed,【%s】' % [e.message])
end
end
# Fake-IP Filter
threads << Thread.new do
begin
if custom_fakeip_filter
Value['dns']['fake-ip-filter-mode'] = fake_ip_filter_mode
if fake_ip_mode == 'fake-ip'
merge_list_from_file(Value['dns'], 'fake-ip-filter', '/etc/openclash/custom/openclash_custom_fake_filter.list')
merge_list_from_file(Value['dns'], 'fake-ip-filter', '/tmp/yaml_openclash_fake_filter_include')
end
end
if fake_ip_mode == 'fake-ip' && (china_ip_route || china_ip6_route)
filter_mode = Value.dig('dns', 'fake-ip-filter-mode')
if filter_mode == 'blacklist' || filter_mode.nil?
filter_rule = 'rule-set:oc-cn-domain'
(Value['dns']['fake-ip-filter'] ||= []) << filter_rule
end
if filter_mode == 'whitelist'
filters = Value.dig('dns', 'fake-ip-filter') || []
deleted_filters = filters.select { |f| f =~ /(geosite:?|rule-set:?).*(@cn|:cn|,cn|:china)/i }
if deleted_filters.any?
Value['dns']['fake-ip-filter'] -= deleted_filters
deleted_filters.each do |f|
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Deleted The Fake-IP-Filter Rule【%s】...' % [f])
end
end
end
if filter_mode == 'rule'
filter_rule = 'RULE-SET,oc-cn-domain,real-ip'
(Value['dns']['fake-ip-filter'] ||= []).unshift(filter_rule)
end
Value['dns']['fake-ip-filter'].uniq!
if filter_mode != 'whitelist'
rule_set_hash = {'rule-providers+'=>{'oc-cn-domain'=>{'type'=>'http', 'interval'=>43200, 'behavior'=>'domain', 'format'=>'mrs', 'url'=>'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/cn.mrs', 'path'=> './rule_provider/oc-cn-domain.mrs'}}}
Value = YAML.overwrite(Value, rule_set_hash)
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【%s】...' % [filter_rule])
end
end
rescue Exception => e
YAML.LOG_ERROR('Set Fake-IP-Filter Failed,【%s】' % [e.message])
end
end
# Custom Hosts
threads << Thread.new do
begin
if custom_host
if (hosts_content = safe_load_yaml('/etc/openclash/custom/openclash_custom_hosts.list')) && !hosts_content.empty?
Value['dns']['use-hosts'] = true
if hosts_content.is_a?(Hash) && hosts_content.key?('hosts')
(Value['hosts'] ||= {}).merge!(hosts_content['hosts'])
else
(Value['hosts'] ||= {}).merge!(hosts_content)
end
YAML.LOG_WARN('You May Need to Turn off The Rebinding Protection Option of Dnsmasq When Hosts Has Set a Reserved Address...')
end
end
rescue Exception => e
YAML.LOG_ERROR('Set Hosts Rules Failed,【%s】' % [e.message])
end
end
# Authentication
threads << Thread.new do
begin
if (auth_config = safe_load_yaml('/tmp/yaml_openclash_auth'))
Value['authentication'] = auth_config
end
rescue Exception => e
YAML.LOG_ERROR('Set authentication Failed,【%s】' % [e.message])
end
end
threads.each(&:join)
begin
threads.clear
# DNS Loop Check
if enable_redirect_dns == '1'
dns_options = ['nameserver', 'fallback', 'default-nameserver', 'proxy-server-nameserver', 'nameserver-policy', 'direct-nameserver', 'proxy-server-nameserver-policy']
dns_options.each do |option|
threads << Thread.new(option) do |opt|
begin
next unless Value['dns'].key?(opt) && !Value['dns'][opt].nil?
if opt != 'nameserver-policy' && opt != 'proxy-server-nameserver-policy'
original_size = Value['dns'][opt].size
Value['dns'][opt].reject! { |v| v.to_s.match?(/^system($|:\/\/)/) }
if Value['dns'][opt].size < original_size
YAML.LOG_TIP('Option【%s】is Setted【system】as DNS Server Which May Cause DNS Loop, Already Remove It...' % [opt])
end
else
Value['dns'][opt].each do |k, v|
if v.is_a?(Array)
original_size = v.size
v.reject! { |z| z.to_s.match?(/^system($|:\/\/)/) }
if v.empty?
Value['dns'][opt].delete(k)
YAML.LOG_TIP('Option【%s - %s】is Setted【system】as DNS Server Which May Cause DNS Loop, Already Remove It...' % [opt, k])
elsif v.size < original_size
YAML.LOG_TIP('Option【%s - %s】is Setted【system】as DNS Server Which May Cause DNS Loop, Already Remove It...' % [opt, k])
end
elsif v.to_s.match?(/^system($|:\/\/)/)
Value['dns'][opt].delete(k)
YAML.LOG_TIP('Option【%s - %s】is Setted【%s】as DNS Server Which May Cause DNS Loop, Already Remove It...' % [opt, k, v.to_s])
end
end
end
rescue Exception => e
YAML.LOG_ERROR('DNS Loop Check,【%s】' % [e.message])
end
end
end
threads.each(&:join)
end
if Value.dig('dns', 'nameserver').to_a.empty?
YAML.LOG_TIP('Detected That The nameserver DNS Option Has No Server Set, Starting To Complete...')
Value['dns']['nameserver'] = ['114.114.114.114', '119.29.29.29', '8.8.8.8', '1.1.1.1']
Value['dns']['fallback'] ||= ['https://dns.cloudflare.com/dns-query', 'https://dns.google/dns-query']
end
if Value['dns'].key?('default-nameserver') && Value['dns']['default-nameserver'].to_a.empty?
YAML.LOG_TIP('Detected That The default-nameserver DNS Option Has No Server Set, Starting To Complete...')
Value['dns']['default-nameserver'] = ['114.114.114.114', '119.29.29.29', '8.8.8.8', '1.1.1.1']
end
# proxy-server-nameserver
local_exclude = (%x{ls -l /sys/class/net/ |awk '{print \$9}' 2>&1}.each_line.map(&:strip) + ['h3=', 'skip-cert-verify=', 'ecs=', 'ecs-override=', 'disable-ipv6=', 'disable-ipv4=', 'disable-qtype-', 'disable-reuse='] + ['utun', 'tailscale0', 'docker0', 'tun163', 'br-lan', 'mihomo']).uniq.join('|')
non_domain_reg = /^dhcp:\/\/|^system($|:\/\/)|([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})/
proxied_server_reg = /^[^#&]+#(?:(?:#{local_exclude})[^&]*&)*(?:(?!(?:#{local_exclude}))[^&]+)/
servers_to_check = Value.dig('dns', 'nameserver').to_a | Value.dig('dns', 'fallback').to_a | Value.dig('dns', 'default-nameserver').to_a
default_proxy_servers = servers_to_check.reject { |s| s.match?(non_domain_reg) }
if ! default_proxy_servers.any? || default_proxy_servers.all? { |x| x.match?(proxied_server_reg) }
default_proxy_servers = ['114.114.114.114', '119.29.29.29', '8.8.8.8', '1.1.1.1']
end
proxy_server_nameserver_policy = Value.dig('dns', 'proxy-server-nameserver-policy') && !Value['dns']['proxy-server-nameserver-policy'].empty?
if Value.dig('dns', 'proxy-server-nameserver').to_a.empty?
all_ns_proxied = Value.dig('dns', 'nameserver').to_a.all? { |x| x.match?(proxied_server_reg) }
if respect_rules || Value.dig('dns', 'respect-rules').to_s == 'true' || all_ns_proxied || proxy_server_nameserver_policy
Value['dns']['proxy-server-nameserver'] = default_proxy_servers
if all_ns_proxied
YAML.LOG_TIP('Nameserver Option Maybe All Setted The Proxy Option, Auto Set Proxy-server-nameserver Option to【%s】For Avoiding Proxies Server Resolve Loop...' % [default_proxy_servers.join(', ')])
elsif proxy_server_nameserver_policy
YAML.LOG_TIP('【Proxy-server-nameserver-policy】Need Proxy-server-nameserver Option Must Be Setted, Auto Set to【%s】' % [default_proxy_servers.join(', ')])
else
YAML.LOG_TIP('【Respect-rules】Need Proxy-server-nameserver Option Must Be Setted, Auto Set to【%s】' % [default_proxy_servers.join(', ')])
end
end
else
all_psn_proxied = Value.dig('dns', 'proxy-server-nameserver').to_a.all? { |x| x.match?(proxied_server_reg) }
if all_psn_proxied
(Value['dns']['proxy-server-nameserver'] ||= []).concat(default_proxy_servers).uniq!
YAML.LOG_TIP('Proxy-server-nameserver Option Maybe All Setted The Proxy Option, Auto Set Proxy-server-nameserver Option to【%s】For Avoiding Proxies Server Resolve Loop...' % [default_proxy_servers.join(', ')])
end
end
rescue Exception => e
YAML.LOG_ERROR('Config File params checked Failed,【%s】' % [e.message])
end
rescue Exception => e
YAML.LOG_ERROR('Config File Overwrite Failed,【%s】' % [e.message])
ensure
begin
YAML.dump(Value, config_file)
rescue Exception => e
YAML.LOG_ERROR('Write file failed:【%s】' % [e.message])
end
File.delete('/tmp/yaml_change_marshal') rescue nil
end
" 2>/dev/null >> $LOG_FILE