#!/bin/sh /etc/rc.common
# Copyright (C) 2020-2022, IrineSistiana
# Copyright (C) 2023-2026, sbwml <admin@cooluc.com>

START=75
USE_PROCD=1

PROG=/usr/bin/mosdns
CONF=$(uci -q get mosdns.config.configfile)
CRON_FILE=/etc/crontabs/root
DUMP_FILE=/etc/mosdns/cache.dump
DUMP_FILE_DEFAULT=/usr/share/mosdns/cache.dump
MOSDNS_SCRIPT=/usr/share/mosdns/mosdns.uc
REDIRECT_LOCK_FILE=/etc/mosdns/redirect.lock

get_config() {
	config_get enabled $1 enabled 0
	config_get adblock $1 adblock 0
	config_get ad_source $1 ad_source ""
	config_get cache $1 cache 0
	config_get cache_size $1 cache_size 8000
	config_get lazy_cache_ttl $1 lazy_cache_ttl 86400
	config_get dump_file $1 dump_file 0
	config_get dump_interval $1 dump_interval 3600
	config_get enable_pipeline $1 enable_pipeline 0
	config_get geo_auto_update $1 geo_auto_update 0
	config_get geo_update_day_time $1 geo_update_day_time 2
	config_get geo_update_week_time $1 geo_update_week_time "*"
	config_get listen_port $1 listen_port 5335
	config_get listen_address $1 listen_address "0.0.0.0"
	config_get log_file $1 log_file "/var/log/mosdns.log"
	config_get log_level $1 log_level "info"
	config_get minimal_ttl $1 minimal_ttl 0
	config_get maximum_ttl $1 maximum_ttl 0
	config_get redirect $1 redirect 0
	config_get local_dns_redirect $1 local_dns_redirect 0
	config_get prefer_ipv4_cn $1 prefer_ipv4_cn 0
	config_get prefer_ipv4 $1 prefer_ipv4 0
	config_get remote_dns $1 remote_dns "tls://8.8.8.8 tls://1.1.1.1"
	config_get custom_local_dns $1 custom_local_dns 0
	config_get apple_optimization $1 apple_optimization 0
	config_get custom_stream_media_dns $1 custom_stream_media_dns 0
	config_get stream_media_dns $1 stream_media_dns "tls://8.8.8.8"
	config_get bootstrap_dns $1 bootstrap_dns "119.29.29.29"
	config_get listen_port_api $1 listen_port_api 52001
	config_get concurrent $1 concurrent 1
	config_get insecure_skip_verify $1 insecure_skip_verify 0
	config_get idle_timeout $1 idle_timeout 30
	config_get enable_ecs_remote $1 enable_ecs_remote 0
	config_get remote_ecs_ip $1 remote_ecs_ip "110.34.181.1"
	config_get dns_leak $1 dns_leak 0
	config_get cloudflare $1 cloudflare 0
	config_get cloudflare_ip $1 cloudflare_ip ""
	config_get reject_type65 $1 reject_type65 "0"
}

generate_config() {
	# jshn shell library
	. /usr/share/libubox/jshn.sh
	# json data
	json_init
	# log
	json_add_object 'log'
	json_add_string "level" "$log_level"
	json_add_string "file" "$log_file"
	json_close_object
	# api
	json_add_object 'api'
	json_add_string "http" "127.0.0.1:$listen_port_api"
	json_close_object
	# include
	json_add_array "include"
	json_close_array
	# plugins
	json_add_array "plugins"
	# plugin: geosite_cn
	json_add_object
	json_add_string "tag" "geosite_cn"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/var/mosdns/geosite_cn.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: geoip_cn
	json_add_object
	json_add_string "tag" "geoip_cn"
	json_add_string "type" "ip_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/var/mosdns/geoip_cn.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: geosite_apple
	json_add_object
	json_add_string "tag" "geosite_apple"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/var/mosdns/geosite_apple.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: geosite_no_cn
	json_add_object
	json_add_string "tag" "geosite_no_cn"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/var/mosdns/geosite_geolocation-!cn.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: whitelist
	json_add_object
	json_add_string "tag" "whitelist"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/whitelist.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: blocklist
	json_add_object
	json_add_string "tag" "blocklist"
	json_add_string "type" "adblock_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/blocklist.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: greylist
	json_add_object
	json_add_string "tag" "greylist"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/greylist.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: ddnslist
	json_add_object
	json_add_string "tag" "ddnslist"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/ddnslist.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: hosts
	json_add_object
	json_add_string "tag" "hosts"
	json_add_string "type" "hosts"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/hosts.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: redirect
	json_add_object
	json_add_string "tag" "redirect"
	json_add_string "type" "redirect"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/redirect.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: adlist
	json_add_object
	json_add_string "tag" "adlist"
	json_add_string "type" "adblock_set"
	json_add_object "args"
	json_add_array "files"
	adlist=$($MOSDNS_SCRIPT get_adlist)
	[ -z "$adlist" ] && adlist="/var/mosdns/disable-ads.txt" # fail-safe
	for list in $adlist; do
		json_add_string "" "$list"
	done
	json_close_array
	json_close_object
	json_close_object
	# plugin: local_ptr
	json_add_object
	json_add_string "tag" "local_ptr"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/local-ptr.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: stream_media
	json_add_object
	json_add_string "tag" "stream_media"
	json_add_string "type" "domain_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/var/mosdns/geosite_disney.txt"
	json_add_string "" "/var/mosdns/geosite_netflix.txt"
	json_add_string "" "/var/mosdns/geosite_hulu.txt"
	json_add_string "" "/etc/mosdns/rule/streaming.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: cloudflare_cidr
	json_add_object
	json_add_string "tag" "cloudflare_cidr"
	json_add_string "type" "ip_set"
	json_add_object "args"
	json_add_array "files"
	json_add_string "" "/etc/mosdns/rule/cloudflare-cidr.txt"
	json_close_array
	json_close_object
	json_close_object
	# plugin: lazy_cache
	[ "$cache" -eq 1 ] && {
		json_add_object
		json_add_string "tag" "lazy_cache"
		json_add_string "type" "cache"
		json_add_object "args"
		json_add_int "size" "$cache_size"
		json_add_int "lazy_cache_ttl" "$lazy_cache_ttl"
		[ "$dump_file" -eq 1 ] && {
			json_add_string "dump_file" "/etc/mosdns/cache.dump"
			json_add_int "dump_interval" "$dump_interval"
		}
		json_close_object
		json_close_object
	}
	# plugin: forward_xinfeng_udp
	json_add_object
	json_add_string "tag" "forward_xinfeng_udp"
	json_add_string "type" "forward"
	json_add_object "args"
	json_add_int "concurrent" 2
	json_add_array "upstreams"
	json_add_object
	json_add_string "addr" "114.114.114.114"
	json_close_object
	json_add_object
	json_add_string "addr" "114.114.115.115"
	json_close_object
	json_close_array
	json_close_object
	json_close_object
	# plugin: forward_local
	json_add_object
	json_add_string "tag" "forward_local"
	json_add_string "type" "forward"
	json_add_object "args"
	json_add_int "concurrent" "$concurrent"
	json_add_array "upstreams"
	local_dns=$($MOSDNS_SCRIPT interface_dns)
	[ -z "$local_dns" ] && local_dns="119.29.29.29 223.5.5.5" # fail-safe
	for addr in $local_dns; do
		enable_http3=0
		if echo "$addr" | grep -q "^h3://"; then
			enable_http3=1
			addr=$(echo $addr | sed 's/h3:\/\//https:\/\//g')
		fi
		json_add_object
		json_add_string "addr" "$addr"
		json_add_string "bootstrap" "$bootstrap_dns"
		json_add_boolean "enable_pipeline" "$enable_pipeline"
		json_add_boolean "insecure_skip_verify" "$insecure_skip_verify"
		json_add_int "idle_timeout" "$idle_timeout"
		[ "$enable_http3" -eq 1 ] && json_add_boolean "enable_http3" "1"
		json_close_object
	done
	json_close_array
	json_close_object
	json_close_object
	# plugin: forward_remote
	json_add_object
	json_add_string "tag" "forward_remote"
	json_add_string "type" "forward"
	json_add_object "args"
	json_add_int "concurrent" "$concurrent"
	json_add_array "upstreams"
	for addr in $remote_dns; do
		enable_http3=0
		if echo "$addr" | grep -q "^h3://"; then
			enable_http3=1
			addr=$(echo $addr | sed 's/h3:\/\//https:\/\//g')
		fi
		json_add_object
		json_add_string "addr" "$addr"
		json_add_string "bootstrap" "$bootstrap_dns"
		json_add_boolean "enable_pipeline" "$enable_pipeline"
		json_add_boolean "insecure_skip_verify" "$insecure_skip_verify"
		json_add_int "idle_timeout" "$idle_timeout"
		[ "$enable_http3" -eq 1 ] && json_add_boolean "enable_http3" "1"
		json_close_object
	done
	json_close_array
	json_close_object
	json_close_object
	# plugin: forward_remote_upstream
	json_add_object
	json_add_string "tag" "forward_remote_upstream"
	json_add_string "type" "sequence"
	json_add_array "args"
	[ "$prefer_ipv4" -eq 1 ] && {
		json_add_object
		json_add_string "exec" "prefer_ipv4"
		json_close_object
	}
	[ "$enable_ecs_remote" -eq 1 ] && {
		json_add_object
		json_add_string "exec" "ecs $remote_ecs_ip"
		json_close_object
	}
	json_add_object
	json_add_string "exec" "\$forward_remote"
	json_close_object
	json_close_array
	json_close_object
	# plugin: forward_stream_media
	json_add_object
	json_add_string "tag" "forward_stream_media"
	json_add_string "type" "forward"
	json_add_object "args"
	json_add_int "concurrent" "$concurrent"
	json_add_array "upstreams"
	for addr in $stream_media_dns; do
		enable_http3=0
		if echo "$addr" | grep -q "^h3://"; then
			enable_http3=1
			addr=$(echo $addr | sed 's/h3:\/\//https:\/\//g')
		fi
		json_add_object
		json_add_string "addr" "$addr"
		json_add_string "bootstrap" "$bootstrap_dns"
		json_add_boolean "enable_pipeline" "$enable_pipeline"
		json_add_boolean "insecure_skip_verify" "$insecure_skip_verify"
		json_add_int "idle_timeout" "$idle_timeout"
		[ "$enable_http3" -eq 1 ] && json_add_boolean "enable_http3" "1"
		json_close_object
	done
	json_close_array
	json_close_object
	json_close_object
	# plugin: forward_stream_media_upstream
	json_add_object
	json_add_string "tag" "forward_stream_media_upstream"
	json_add_string "type" "sequence"
	json_add_array "args"
	[ "$prefer_ipv4" -eq 1 ] && {
		json_add_object
		json_add_string "exec" "prefer_ipv4"
		json_close_object
	}
	[ "$enable_ecs_remote" -eq 1 ] && {
		json_add_object
		json_add_string "exec" "ecs $remote_ecs_ip"
		json_close_object
	}
	json_add_object
	json_add_string "exec" "\$forward_stream_media"
	json_close_object
	json_close_array
	json_close_object
	# plugin: modify_ttl
	json_add_object
	json_add_string "tag" "modify_ttl"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "exec" "ttl $minimal_ttl-$maximum_ttl"
	json_close_object
	json_close_array
	json_close_object
	# plugin: modify_ddns_ttl
	json_add_object
	json_add_string "tag" "modify_ddns_ttl"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "exec" "ttl 5-5"
	json_close_object
	json_close_array
	json_close_object
	# plugin: has_resp_sequence
	json_add_object
	json_add_string "tag" "has_resp_sequence"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "matches" "qname \$ddnslist"
	json_add_string "exec" "\$modify_ddns_ttl"
	json_close_object
	json_add_object
	json_add_string "matches" "!qname \$ddnslist"
	json_add_string "exec" "\$modify_ttl"
	json_close_object
	[ "$cloudflare" -eq 1 ] && {
		json_add_object
		json_add_array "matches"
		json_add_string "" "!qname \$whitelist"
		json_add_string "" "!qname \$greylist"
		json_add_string "" "!qname \$stream_media"
		json_add_string "" "resp_ip \$cloudflare_cidr"
		json_close_array
		json_add_string "exec" "black_hole $cloudflare_ip"
		json_close_object
	}
	json_add_object
	json_add_string "matches" "has_resp"
	json_add_string "exec" "accept"
	json_close_object
	json_close_array
	json_close_object
	# plugin: query_is_non_local_ip
	json_add_object
	json_add_string "tag" "query_is_non_local_ip"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "exec" "\$forward_local"
	json_close_object
	json_add_object
	json_add_string "matches" "!resp_ip \$geoip_cn"
	json_add_string "exec" "drop_resp"
	json_close_object
	json_close_array
	json_close_object
	# plugin: fallback
	json_add_object
	json_add_string "tag" "fallback"
	json_add_string "type" "fallback"
	json_add_object "args"
	[ "$dns_leak" -eq 1 ] && json_add_string "primary" "forward_remote_upstream" || json_add_string "primary" "query_is_non_local_ip"
	json_add_string "secondary" "forward_remote_upstream"
	json_add_int "threshold" 500
	json_add_boolean "always_standby" 1
	json_close_object
	json_close_object
	# plugin: apple_domain_fallback
	json_add_object
	json_add_string "tag" "apple_domain_fallback"
	json_add_string "type" "fallback"
	json_add_object "args"
	json_add_string "primary" "query_is_non_local_ip"
	json_add_string "secondary" "forward_xinfeng_udp"
	json_add_int "threshold" 100
	json_add_boolean "always_standby" 1
	json_close_object
	json_close_object
	# plugin: query_is_apple_domain
	json_add_object
	json_add_string "tag" "query_is_apple_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "matches" "!qname \$geosite_apple"
	json_add_string "exec" "return"
	json_close_object
	json_add_object
	json_add_string "exec" "\$apple_domain_fallback"
	json_close_object
	json_close_array
	json_close_object
	# plugin: query_is_ddns_domain
	json_add_object
	json_add_string "tag" "query_is_ddns_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "matches" "qname \$ddnslist"
	json_add_string "exec" "\$forward_local"
	json_close_object
	json_close_array
	json_close_object
	# plugin: query_is_local_domain
	json_add_object
	json_add_string "tag" "query_is_local_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	[ "$prefer_ipv4_cn" -eq 1 ] && {
		json_add_object
		json_add_string "exec" "prefer_ipv4"
		json_close_object
	}
	json_add_object
	json_add_string "matches" "qname \$geosite_cn"
	json_add_string "exec" "\$forward_local"
	json_close_object
	json_close_array
	json_close_object
	# plugin: query_is_no_local_domain
	json_add_object
	json_add_string "tag" "query_is_no_local_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "matches" "qname \$geosite_no_cn"
	json_add_string "exec" "\$forward_remote_upstream"
	json_close_object
	json_close_array
	json_close_object
	# plugin: query_is_whitelist_domain
	json_add_object
	json_add_string "tag" "query_is_whitelist_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	[ "$prefer_ipv4_cn" -eq 1 ] && {
		json_add_object
		json_add_string "exec" "prefer_ipv4"
		json_close_object
	}
	json_add_object
	json_add_string "matches" "qname \$whitelist"
	json_add_string "exec" "\$forward_local"
	json_close_object
	json_close_array
	json_close_object
	# plugin: query_is_greylist_domain
	json_add_object
	json_add_string "tag" "query_is_greylist_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "matches" "qname \$greylist"
	json_add_string "exec" "\$forward_remote_upstream"
	json_close_object
	json_close_array
	json_close_object
	# plugin: query_is_reject_domain
	json_add_object
	json_add_string "tag" "query_is_reject_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "matches" "qname \$blocklist"
	json_add_string "exec" "reject 3"
	json_close_object
	json_add_object
	json_add_string "matches" "qname \$adlist"
	json_add_string "exec" "reject 3"
	json_close_object
	json_add_object
	json_add_array "matches"
	json_add_string "" "qtype 12"
	json_add_string "" "qname \$local_ptr"
	json_close_array
	json_add_string "exec" "reject 3"
	json_close_object
	[ "$reject_type65" -eq 1 ] && {
		json_add_object
		json_add_string "matches" "qtype 65"
		json_add_string "exec" "reject 3"
		json_close_object
	}
	json_close_array
	json_close_object
	# plugin: query_is_stream_media_domain
	json_add_object
	json_add_string "tag" "query_is_stream_media_domain"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "matches" "qname \$stream_media"
	json_add_string "exec" "\$forward_stream_media_upstream"
	json_close_object
	json_close_array
	json_close_object
	# plugin: main_sequence
	json_add_object
	json_add_string "tag" "main_sequence"
	json_add_string "type" "sequence"
	json_add_array "args"
	json_add_object
	json_add_string "exec" "\$hosts"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	[ "$cache" -eq 1 ] && {
		json_add_object
		json_add_array "matches"
		json_add_string "" "!qname \$ddnslist"
		json_add_string "" "!qname \$blocklist"
		json_add_string "" "!qname \$adlist"
		json_add_string "" "!qname \$local_ptr"
		json_close_array
		json_add_string "exec" "\$lazy_cache"
		json_close_object
		json_add_object
		json_add_string "exec" "jump has_resp_sequence"
		json_close_object
	}
	json_add_object
	json_add_string "exec" "\$redirect"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	json_add_object
	[ "$apple_optimization" -eq 1 ] && {
		json_add_string "exec" "\$query_is_apple_domain"
		json_close_object
		json_add_object
		json_add_string "exec" "jump has_resp_sequence"
		json_close_object
		json_add_object
	}
	json_add_string "exec" "\$query_is_ddns_domain"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	json_add_object
	json_add_string "exec" "\$query_is_whitelist_domain"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	json_add_object
	json_add_string "exec" "\$query_is_reject_domain"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	json_add_object
	json_add_string "exec" "\$query_is_greylist_domain"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	[ "$custom_stream_media_dns" -eq 1 ] && {
		json_add_object
		json_add_string "exec" "\$query_is_stream_media_domain"
		json_close_object
		json_add_object
		json_add_string "exec" "jump has_resp_sequence"
		json_close_object
	}
	json_add_object
	json_add_string "exec" "\$query_is_local_domain"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	json_add_object
	json_add_string "exec" "\$query_is_no_local_domain"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	json_add_object
	json_add_string "exec" "\$fallback"
	json_close_object
	json_add_object
	json_add_string "exec" "jump has_resp_sequence"
	json_close_object
	json_close_array
	json_close_object
	# plugin: udp_server
	json_add_object
	json_add_string "tag" "udp_server"
	json_add_string "type" "udp_server"
	json_add_object "args"
	json_add_string "entry" "main_sequence"
	json_add_string "listen" "$listen_address:$listen_port"
	json_close_object
	json_close_object
	# plugin: tcp_server
	json_add_object
	json_add_string "tag" "tcp_server"
	json_add_string "type" "tcp_server"
	json_add_object "args"
	json_add_string "entry" "main_sequence"
	json_add_string "listen" "$listen_address:$listen_port"
	json_close_object
	json_close_object
	# close plugins array
	json_close_array
	# print json
	json_dump > /var/etc/mosdns.json

	# init dump_file
	[ "$dump_file" -eq 1 ] && [ ! -f $DUMP_FILE ] && cp -a $DUMP_FILE_DEFAULT $DUMP_FILE
	[ "$dump_file" -eq 0 ] && \cp -a $DUMP_FILE_DEFAULT $DUMP_FILE
}

service_triggers() {
	procd_add_reload_trigger "mosdns"
}

dhcp_setting() {
	[ ! -f "$REDIRECT_LOCK_FILE" ] && {
		printf "rebind_protection=$(uci -q get dhcp.@dnsmasq[0].rebind_protection)\n"
		printf "rebind_localhost=$(uci -q get dhcp.@dnsmasq[0].rebind_localhost)\n"
		printf "noresolv=$(uci -q get dhcp.@dnsmasq[0].noresolv)\n"
		printf "resolvfile=$(uci -q get dhcp.@dnsmasq[0].resolvfile)\n"
		printf "cachesize=$(uci -q get dhcp.@dnsmasq[0].cachesize)\n"
	} > $REDIRECT_LOCK_FILE

	if [ "${CONF}" = "/var/etc/mosdns.json" ]; then
		sed -i "/list server/d" /etc/config/dhcp
		uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#$listen_port"
		uci set dhcp.@dnsmasq[0].rebind_protection='0'
		uci set dhcp.@dnsmasq[0].noresolv="1"
		uci set dhcp.@dnsmasq[0].cachesize='0'
		uci commit dhcp
	else
		sed -i "/list server/d" /etc/config/dhcp
		uci add_list dhcp.@dnsmasq[0].server="127.0.0.1#$(awk -F'[:" ]+' '/^\s+listen:/{for(i=1;i<=NF;i++){if($i~/^[0-9]+$/){print $i;exit}}}' $CONF)"
		uci set dhcp.@dnsmasq[0].rebind_protection='0'
		uci set dhcp.@dnsmasq[0].noresolv="1"
		uci set dhcp.@dnsmasq[0].cachesize='0'
		uci commit dhcp
	fi
}

uci_set_or_del() {
	local key="$1"
	local val="$2"

	if [ -n "$val" ]; then
		uci set "$key=$val"
	else
		uci del "$key"
	fi
}

restore_dhcp_setting() {
	if [ -f "$REDIRECT_LOCK_FILE" ]; then
		sed -i "/list server/d" /etc/config/dhcp
		source "$REDIRECT_LOCK_FILE"

		uci_set_or_del dhcp.@dnsmasq[0].rebind_protection "$rebind_protection"
		uci_set_or_del dhcp.@dnsmasq[0].resolvfile "$resolvfile"
		uci_set_or_del dhcp.@dnsmasq[0].rebind_localhost "$rebind_localhost"
		uci_set_or_del dhcp.@dnsmasq[0].noresolv "$noresolv"
		uci_set_or_del dhcp.@dnsmasq[0].cachesize "$cachesize"

		uci commit dhcp
		rm -f "$REDIRECT_LOCK_FILE"
	fi
}

reload_dnsmasq() {
	[ "$(/etc/init.d/dnsmasq status)" = "running" ] && /etc/init.d/dnsmasq reload
}

reload_service() {
	stop
	sleep 1
	start
}

setcron() {
	sed -i '/mosdns.uc/d' $CRON_FILE 2>/dev/null
	[ "$geo_auto_update" -eq 1 ] && echo "0 $geo_update_day_time * * $geo_update_week_time /usr/share/mosdns/mosdns.uc update" >> $CRON_FILE
	crontab $CRON_FILE
}

delcron() {
	sed -i '/mosdns.uc/d' $CRON_FILE 2>/dev/null
	crontab $CRON_FILE
}

start_service() {
	config_load "mosdns"
	config_foreach get_config "mosdns"
	[ $enabled -ne 1 ] && return 1
	delcron ; setcron

	rm -rf /tmp/log/mosdns*

	$MOSDNS_SCRIPT v2dat_dump

	[ "${CONF}" = "/var/etc/mosdns.json" ] && generate_config

	procd_open_instance mosdns
	procd_set_param env QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING=true
	procd_set_param command $PROG start
	procd_append_param command -c "$CONF"
	procd_append_param command -d "/etc/mosdns"
	procd_set_param stdout 1
	procd_set_param stderr 1
	procd_set_param respawn
	procd_close_instance mosdns

	[ "$redirect" -ne 1 ] && restore_dhcp_setting
	[ "$redirect" -eq 1 ] && dhcp_setting
	reload_dnsmasq

	# dns hijack
	if [ "$local_dns_redirect" -eq 1 ] && [ -f "/sbin/fw4" ]; then
		! nft --check list table inet mosdns > "/dev/null" 2>&1 || \
			nft delete table inet mosdns
		nft add table inet mosdns
		nft add chain inet mosdns prerouting "{ type nat hook prerouting priority -95; policy accept; }"
		nft add rule inet mosdns prerouting "meta nfproto { ipv4, ipv6 } udp dport 53 counter redirect to :$listen_port comment \"DNS HIJACK\""
	fi

	# Update Adlist
	update_list=0
	if [ "$adblock" -eq 1 ]; then
		if [ -f "/etc/mosdns/rule/.ad_source" ]; then
			for url in $ad_source; do
				if [ "$url" = "geosite.dat" ] ||[ $(echo "$url" | grep -c -E "^file://") -eq 1 ]; then
					continue
				fi
				if [ $(grep -c "$url" "/etc/mosdns/rule/.ad_source") -eq 0 ]; then
					update_list=1
					break
				fi
			done
		else
			update_list=1
		fi
	fi

	[ "$update_list" -eq 1 ] && $MOSDNS_SCRIPT update_adlist &
}

stop_service() {
	config_load "mosdns"
	config_foreach get_config "mosdns"
	[ "$enabled" -eq "0" ] && restore_dhcp_setting
	! nft --check list table inet mosdns > "/dev/null" 2>&1 || \
		nft delete table inet mosdns
	reload_dnsmasq
	delcron
}
