small-package/luci-app-dnscrypt-proxy2/files/dnscrypt-proxy.init

465 lines
18 KiB
Bash

#!/bin/sh /etc/rc.common
#
# Copyright (C) 2019 p.t. <peter-tank@github.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
START=30
USE_PROCD=1
INIT_TRACE=
EXTRA_COMMANDS=
PROG=/usr/sbin/dnscrypt-proxy
CONFIG_DIR=/var/etc
USER=nobody
NAME=dnscrypt-proxy
SERVICE_DAEMONIZE=
SERVICE_USE_PID=1
SERVICE_MATCH_EXEC=1
SERVICE_STOP_TIME=15
SERVICE_PID_FILE=/var/run/$NAME.pid
LUCI_STATUS=/var/run/luci-reload-status
LOG_FILE="/var/etc/dnscrypt"
CACHE_DIR="/usr/share/dnscrypt-proxy"
DIRECT_IPSETS="vpsiplist localnetwork ss_spec_wan_ac"
# has side effects when there is a option names the same 'addrs' in shadowsocksr config file
# keep this uci function excuted at the bottom of scripts
uci_filter_resolver_addrs() {
local __PKGNAME="${NAME}"
local __SECTIONTYPE="server_addr"
local ret
filter_resolver_addrs()
{
local __TYPE="$1"
local __OPTION="$2"
set | sed -ne "s/^CONFIG_.*_addrs='\([^']*\)'$/\1/p" | sed -e "s/[, ]/\n/g" | sort | uniq
}
# config_load "${__PKGNAME}"
# tricky way first for all server_addr addrs in DNSCrypt ACL
ret=$(filter_resolver_addrs "${__SECTIONTYPE}" "addrs")
# or get all addrs from all resolvers configured.
[ -z "${ret}" ] && {
CONFIG_APPEND=1
config_list_foreach "ns1" "resolvers" config_load
ret=$(filter_resolver_addrs ".*" "addrs")
}
echo "${ret}"
}
uci_get_by_name() {
local ret=$(uci get dnscrypt-proxy.$1.$2 2>/dev/null)
echo "${ret:=$3}"
}
boot() {
dnscrypt_boot=1
rc_procd start_service
}
dnscrypt_instance() {
local config_path="$CONFIG_DIR/dnscrypt-proxy-$1.conf"
[ $(uci_get_by_name "$1" enable 0) -eq 1 ] || return 0
create_config_file $1 "$config_path"
procd_open_instance
procd_set_param command $PROG -config "$config_path" -pidfile "$SERVICE_PID_FILE"
procd_set_param file "$config_path"
procd_close_instance
}
include_for_firewall_reload() {
local FWI=$(uci get firewall.dnscrypt_proxy.path 2>/dev/null)
[ -n "$FWI" ] || return 0
echo '#!/bin/sh' >$FWI
cat <<-EOF >>"$FWI"
addr_filter=\$(uci get ${NAME}.ns1.addr_filter 2>/dev/null)
if [ "\${addr_filter:-auto}" == "auto" ]; then
for list in ${DIRECT_IPSETS}; do
ipset list -n "\${list}" >/dev/null 2>&1
[ \$? -eq 0 ] && addr_filter="\${list}" && break
done
fi
ipset list -n "\${addr_filter}" >/dev/null 2>&1 && {
ipset_shell=\$(find ${CONFIG_DIR} -name "dnscrypt_filter2_*.sh" | head -n1)
[ -z "\${ipset_shell}" ] || {
sed -i 's/^ipset add [^ ]* \(.*\)$/ipset add '"\${addr_filter}"' \1/g' "\${ipset_shell}"
echo "### \$(date) on firewall reload" >> "${LOG_FILE}.log"
echo "### appending resolver addresses to ipset list \${addr_filter}..." >> "${LOG_FILE}.log"
wc -l "\${ipset_shell}" >> "${LOG_FILE}.log" 2>&1
date >"\${ipset_shell}.log"
\${ipset_shell} >>"\${ipset_shell}.log" 2>&1 &
}
}
EOF
}
create_config_file() {
local server_names listen_address query_meta max_clients bootstrap_resolvers netprobe_address
local disabled_server_names log_file log_level timeout keepalive cert_refresh_delay netprobe_timeout
local log_files_max_size log_files_max_age log_files_max_backups reject_ttl
local reject_ttl cache_size cache_min_ttl cache_max_ttl cache_neg_min_ttl cache_neg_max_ttl
local lb_strategy blocked_query_response force_defaults force_gets
local proxy http_proxy cloaking_rules cloak_ttl
local config_path="$2"
local dstf two_line_header forward_resolvers
[ ! -d "$CONFIG_DIR" ] && mkdir -p "$CONFIG_DIR"
[ -d "${CACHE_DIR}" ] || mkdir -p "${CACHE_DIR}"
[ -f "$config_path" ] && rm "$config_path"
config_get server_names $1 'server_names' ''
config_get listen_addresses $1 'listen_addresses' '127.0.0.1:5335'
config_get query_meta $1 'query_meta' ''
config_get max_clients $1 'max_clients' '250'
config_get bootstrap_resolvers $1 'bootstrap_resolvers' '114.114.114.114:53'
config_get netprobe_address $1 'netprobe_address' '114.114.114.114:53'
config_get disabled_server_names $1 'disabled_server_names' ''
config_get log_file $1 'log_file' "${LOG_FILE}.log"
config_get log_level $1 'log_level' '2'
config_get timeout $1 'timeout' '5000'
config_get keepalive $1 'keepalive' '30'
config_get cert_refresh_delay $1 'cert_refresh_delay' '240'
config_get netprobe_timeout $1 'netprobe_timeout' '60'
config_get log_files_max_size $1 'log_files_max_size' '1'
config_get log_files_max_age $1 'log_files_max_age' '7'
config_get log_files_max_backups $1 'log_files_max_backups' '1'
config_get reject_ttl $1 'reject_ttl' '600'
config_get cache_size $1 'cache_size' '512'
config_get cache_min_ttl $1 'cache_min_ttl' '600'
config_get cache_max_ttl $1 'cache_max_ttl' '86400'
config_get cache_neg_min_ttl $1 'cache_neg_min_ttl' '60'
config_get cache_neg_max_ttl $1 'cache_neg_max_ttl' '600'
config_get lb_strategy $1 'lb_strategy' 'p2'
config_get blocked_query_response $1 'blocked_query_response' 'hinfo'
config_get proxy $1 'proxy' ''
config_get http_proxy $1 'http_proxy' ''
config_get cloak_ttl $1 'cloak_ttl' '600'
append_str_param "user_name" "$USER" $config_path
append_multivalue_param "server_names" "$server_names" $config_path
append_multivalue_param "listen_addresses" "$listen_addresses" $config_path
append_multivalue_param "query_meta" "$query_meta" $config_path
append_param "max_clients" "$max_clients" $config_path
append_multivalue_param "bootstrap_resolvers" "$bootstrap_resolvers" $config_path
append_str_param "netprobe_address" "$netprobe_address" $config_path
append_multivalue_param "disabled_server_names" "$disabled_server_names" $config_path
append_param "log_level" "$log_level" $config_path
append_str_param "log_file" "$log_file" $config_path
append_param "timeout" "$timeout" $config_path
append_param "cert_refresh_delay" "$cert_refresh_delay" $config_path
append_param "netprobe_timeout" "$netprobe_timeout" $config_path
append_param "log_files_max_size" "$log_files_max_size" $config_path
append_param "log_files_max_age" "$log_files_max_age" $config_path
append_param "log_files_max_backups" "$log_files_max_backups" $config_path
append_param "reject_ttl" "$reject_ttl" $config_path
append_param "cache_size" "$cache_size" $config_path
append_param "cache_min_ttl" "$cache_min_ttl" $config_path
append_param "cache_max_ttl" "$cache_max_ttl" $config_path
append_param "cache_neg_min_ttl" "$cache_neg_min_ttl" $config_path
append_param "cache_neg_max_ttl" "$cache_neg_max_ttl" $config_path
append_str_param "lb_strategy" "$lb_strategy" $config_path
append_str_param "blocked_query_response" "$blocked_query_response" $config_path
append_str_param "proxy" "$proxy" $config_path
append_str_param "http_proxy" "$http_proxy" $config_path
append_param "cloak_ttl" "$cloak_ttl" $config_path
force_defaults='
lb_estimator,true
ignore_system_dns,true
block_unqualified,true
block_undelegated,true
ipv4_servers,true
ipv6_servers,false
block_ipv6,true
dnscrypt_servers,true
doh_servers,true
require_dnssec,false
force_tcp,false
require_nolog,true
require_nofilter,true
cache,true
offline_mode,false
dnscrypt_ephemeral_keys,false
tls_disable_session_tickets,false
cert_ignore_timestamp,true
'
append_yes_no() {
local sets=$1
local defs=$2
local config_path=$3
local line param_name param_value val
for line in $defs; do
param_name="${line%%,*}"; param_value="${line##*,}";
for val in $sets; do
[[ x$val == x$param_name ]] && param_value=true
done
echo "$param_name = $param_value" >> $config_path
done
}
config_get force_gets $1 'force' ''
append_yes_no "$force_gets" "$force_defaults" "$config_path"
handle_list_file() {
local file
local fwd="$2"
if [ x"${1:0:4}" == x"http" ]; then file=$(cache_file "${1}" 0);
elif [ x"${1:0:1}" == x"/" ]; then file="${1}";
else file="$CACHE_DIR/${1}";
fi
[ x"$file" == x -o ! -f "${file}" ] && return
local tmpf="/tmp/dnscrypt_${file##*/}"
if [ x"${file##*.}" == xconf -o x"${file##*.}" == xadblock ]; then
sed -ne "s/^\(address\|server\)=\/\([^/]*\)\/.*$/\2 $fwd/p" -e "s/ *$//g" "$file" > "$tmpf"
else
[ -z "$fwd" ] || sed -i -e "s/$/ $fwd/g" "$tmpf"
cat "$file" > "$tmpf"
fi
echo "$tmpf"
}
append_list_file() {
local sec=$1
local list=$2
local param_name=$3
local txtf=$4
local log=$5
local config_path=$6
local line2=$7
local fwd=$8
echo -e $line2 > "$txtf"
[ -z "$log" ] || {
append_str_param "log_file" "${LOG_FILE}_$log" $config_path
append_str_param "log_format" "tsv" $config_path
}
merg_list_file() {
local src=${1%% *}
local list_file
list_file=$(handle_list_file $src "$fwd")
[[ x"$list_file" == x ]] && return 0
cat "$list_file" >> "$txtf"
}
config_list_foreach "$sec" "$list" merg_list_file $config_path
line=$(sort "$txtf" | uniq); echo "$line" > "$txtf"
line=$(cat "$txtf" | wc -l); [ $line -le 2 ] && rm -f "$txtf" && return
echo "#total $((line-1)) uniq items." >> "$txtf"
append_str_param "$param_name" "$txtf" $config_path
}
dstf="$CONFIG_DIR/dnscrypt_forwarding_rules.txt"
two_line_header='#dnscrypt forwarding rule file.\n'
forward_resolvers="$bootstrap_resolvers"
append_list_file $1 "forwarding_rules" "forwarding_rules" "$dstf" "" $config_path "$two_line_header" $forward_resolvers
dstf="$CONFIG_DIR/dnscrypt_cloaking_rules.txt"
two_line_header='#dnscrypt cloaking rules file.\n'
append_list_file $1 "cloaking_rules" "cloaking_rules" "$dstf" "" $config_path "$two_line_header"
echo "[query_log]" >> $config_path
append_str_param "file" "${LOG_FILE}_query.log" $config_path
append_str_param "format" "tsv" $config_path
echo "[nx_log]" >> $config_path
append_str_param "file" "${LOG_FILE}_nx.log" $config_path
append_str_param "format" "tsv" $config_path
echo "[blocked_names]" >> $config_path
dstf="$CONFIG_DIR/dnscrypt_blocked_names.txt"
two_line_header='#dnscrypt domain black list file.\n*.test\n*.onion\n*.localhost\n*.local\n*.invalid\n*.bind\n*.lan\n*.internal\n*.intranet\n*.private\n*.workgroup\n*.10.in-addr.arpa\n*.16.172.in-addr.arpa\n*.168.192.in-addr.arpa\n*.254.169.in-addr.arpa\n*.d.f.ip6.arpa'
append_list_file $1 "blocked_names" "blocked_names_file" "$dstf" "bd.log" $config_path "$two_line_header"
echo "[blocked_ips]" >> $config_path
dstf="$CONFIG_DIR/dnscrypt_blocked_ips.txt"
two_line_header='#dnscrypt ip black list file.\n127.*\n192.168.*'
append_list_file $1 "blocked_ips" "blocked_ips_file" "$dstf" "bi.log" $config_path "$two_line_header"
echo "[allowed_names]" >> $config_path
dstf="$CONFIG_DIR/dnscrypt_allowed_names.txt"
two_line_header='#dnscrypt white list file.\n'
append_list_file $1 "allowed_names" "allowed_names_file" "$dstf" "wd.log" $config_path "$two_line_header"
echo "[static]" >> $config_path
append_static_resolver() {
local sdns=$1
local config_path=$2
local sdns
[[ "x$sdns" == x ]] && return 0
echo "[static.'$sdns']" >> $config_path
append_str_param "sdns" "$sdns" $config_path
}
config_list_foreach "$1" "sdns" append_static_resolver $config_path
echo "[sources]" >> $config_path
append_resolvers_source() {
local resolver=$1
local config_path=$2
local section="global"
local urls cache_file minisign_key prefix selfsign details_json
config_unset $section "urls"
[ -f "/etc/config/${resolver}" ] || return 0
config_load ${resolver}
[ $? -eq 0 ] || return 0
config_get urls $section 'urls' ''
[[ "x$urls" == x ]] && return 0
echo "[sources.'${resolver}']" >> $config_path
config_get urls $section 'urls' ''
config_get format $section 'format' 'v2'
config_get cache_file $section 'cache_file' "${urls##*/}"
config_get minisign_key $section 'minisign_key' 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
config_get prefix $section 'prefix' ''
config_get details_json $section 'details_json' "${cache_file%%.md}.json"
config_get_bool cache_mode $section 'cache_mode' '1'
config_get_bool selfsign $section 'selfsign' '0'
if [ $cache_mode -eq 1 ] ; then
local redirect_https site_addr schema port
redirect_https="$(uci_get uhttpd main redirect_https '0')"
site_addr="$(uci_get uhttpd main listen_https '[::]:80')"
schema=http
port=${site_addr##*:}
[ x"${port}" != "x80" -a $redirect_https -eq 1 ] && opkg list-installed | grep libustream-openssl && schema=https
[ x"${port}" == "x80" -o x"${port}" == "x443" ] && port=
urls="${schema}://localhost${port:+:${port}}/${urls##*/}"
fi
append_multivalue_param "urls" "$urls" $config_path
append_str_param "format" "$format" $config_path
append_str_param "cache_file" "$cache_file" $config_path
append_str_param "minisign_key" "$minisign_key" $config_path
append_str_param "prefix" "$prefix" $config_path
config_get_bool selfsign $section 'selfsign' '0'
config_get details_json $section 'details_json' ''
}
config_list_foreach "$1" "resolvers" append_resolvers_source $config_path
}
multivalue_parse() {
local param_values=$(echo $1 | sed -e 's/[, ]/\n/g' -e 's/\n\n/\n/g')
[[ x == "x${param_values}" ]] && echo -n "[]" && return 1
local p
p=$(for p in ${param_values}; do echo -n "'${p}'"; done)
echo -n "["
echo -n $p | sed -e "s/''/', '/g"
echo -n "]"
}
log_ignored_param() {
local param_name=$1
logger -t dnscrypt-proxy -p user.warn "dnscrypt-proxy plugins support not present, ignoring '$param_name' parameter."
}
append_multivalue_param() {
local param_name=$1
local param_value=$2
local config_path=$3
echo "$param_name = $(multivalue_parse $param_value)" >> $config_path
}
append_str_param() {
local param_name=$1
local param_value=$2
local config_path=$3
echo "$param_name = '$param_value'" >> $config_path
}
append_param() {
local param_name=$1
local param_value=$2
local config_path=$3
echo "$param_name = $param_value" >> $config_path
}
start_service() {
config_load dnscrypt-proxy
local addr_filter list
config_get addr_filter ns1 'addr_filter' 'auto'
if [ "${addr_filter}" == "auto" ]; then
for list in ${DIRECT_IPSETS}; do
ipset list -n "${list}" >/dev/null 2>&1
[ $? -eq 0 ] && addr_filter="${list}" && break
done
fi
ipset list -n "${addr_filter}" >/dev/null 2>&1 && {
local ipset_shell="${CONFIG_DIR}/dnscrypt_filter2_${addr_filter}.sh"
uci_filter_resolver_addrs > "${ipset_shell}"
sed -i 's/^\(.*\)$/ipset add '"${addr_filter}"' "\1" nomatch/g' "${ipset_shell}"
chmod +x "${ipset_shell}"
echo "### appending resolver addresses to ipset list ${addr_filter}..." >> "${LOG_FILE}.log"
wc -l "${ipset_shell}" >> "${LOG_FILE}.log" 2>&1
date >"${ipset_shell}.log"
${ipset_shell} >>"${ipset_shell}.log" 2>&1 &
}
include_for_firewall_reload
config_foreach dnscrypt_instance dnscrypt-proxy
}
service_triggers() {
procd_add_reload_trigger 'dnscrypt-proxy'
}
reload_service() {
stop
start
}
cache_file() {
local tdl=$1
local key=$2
local root=$3
local mode=${4:-0}
[ -n "$root" ] && tdl=$tdl$'\n'$tdl.minisig
for cdl in $tdl; do
echo "INFO: details[$cdl]" > $LUCI_STATUS && sleep 3
local md5=$(echo $cdl | md5sum | cut -d' ' -f1)
local fn="$CACHE_DIR/${md5}_${cdl##*/}"
local tmpf="/tmp/dnscrypt_${cdl##*/}.dl"
local line
[ ! -f "$fn" ] && {
wget -q --no-check-certificate -t 3 -T 30 -O "$tmpf" "$cdl"
[ $? -eq 0 ] || return
line=$(cat "$tmpf" | wc -l)
[ $line -gt 1 ] || return
cat /dev/null > "$fn"
[ -z "$key" -o $mode -eq 11 ] && echo "##source[#$line]: $cdl" >> "$fn"
cat "$tmpf" >> "$fn"
}
[ $mode -ge 10 ] && cat "$fn" > $root/${cdl##*/}
done
echo "${fn%%.minisig}"
}