#!/bin/sh /etc/rc.common # # Copyright (C) 2018-2024 Ruilin Peng (Nick) . # # smartdns is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # smartdns is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . START=19 STOP=82 NAME=smartdns-lite USE_PROCD=1 SMARTDNS_CONF_DIR="/etc/smartdns" SMARTDNS_CONF_DOWNLOAD_DIR="$SMARTDNS_CONF_DIR/conf.d" SMARTDNS_VAR_CONF_DIR="/var/etc/smartdns" SMARTDNS_CONF="$SMARTDNS_VAR_CONF_DIR/smartdns-lite.conf" CUSTOM_CONF="$SMARTDNS_CONF_DIR/custom.conf" SMARTDNS_CONF_TMP="${SMARTDNS_CONF}.tmp" EXTRA_COMMANDS="clear_rules" EXTRA_HELP=" clear_rules clear all rules" conf_append() { echo "$1 $2" >> $SMARTDNS_CONF_TMP } client_rule_addr_append() { conf_append "client-rules" "$1" } servers_append() { conf_append "server" "$1 $server_options" } setup_tproxy_rules() { local tproxy_port="$1" local table_type="$2" ip rule add fwmark 1104 lookup 981 ip route add local 0.0.0.0/0 dev lo table 981 ip -6 route add local ::/0 dev lo table 981 if [ "$table_type" = "iptable" ]; then iptables -t mangle -N SMARTDNS_LITE iptables -t mangle -A SMARTDNS_LITE -p tcp -m set --match-set smartdns dst -j TPROXY --on-ip 127.0.0.1 --on-port ${tproxy_port} --tproxy-mark 1104 iptables -t mangle -A SMARTDNS_LITE -p udp -m set --match-set smartdns dst -j TPROXY --on-ip 127.0.0.1 --on-port ${tproxy_port} --tproxy-mark 1104 iptables -t mangle -A SMARTDNS_LITE -j ACCEPT iptables -t mangle -A PREROUTING -j SMARTDNS_LITE ip6tables -t mangle -N SMARTDNS_LITE ip6tables -t mangle -A SMARTDNS_LITE -p tcp -m set --match-set smartdns6 dst -j TPROXY --on-ip ::1 --on-port ${tproxy_port} --tproxy-mark 1104 ip6tables -t mangle -A SMARTDNS_LITE -p udp -m set --match-set smartdns6 dst -j TPROXY --on-ip ::1 --on-port ${tproxy_port} --tproxy-mark 1104 ip6tables -t mangle -A SMARTDNS_LITE -j ACCEPT ip6tables -t mangle -A PREROUTING -j SMARTDNS_LITE elif [ "$table_type" = "nftable" ]; then nft add table ip smartdns_lite nft add set ip smartdns_lite ipv4 { type ipv4_addr\; flags interval\; auto-merge\; } nft add chain ip smartdns_lite prerouting { type filter hook prerouting priority 0\; } nft add rule ip smartdns_lite prerouting meta l4proto tcp ip daddr @ipv4 tproxy to 127.0.0.1:${tproxy_port} mark set 1104 nft add rule ip smartdns_lite prerouting meta l4proto udp ip daddr @ipv4 tproxy to 127.0.0.1:${tproxy_port} mark set 1104 nft add table ip6 smartdns_lite nft add set ip6 smartdns_lite ipv6 { type ipv6_addr\; flags interval\; auto-merge\; } nft add chain ip6 smartdns_lite prerouting6 { type filter hook prerouting priority 0\; } nft add rule ip6 smartdns_lite prerouting6 meta l4proto tcp ip6 daddr @ipv6 tproxy to ::1:${tproxy_port} mark set 1104 nft add rule ip6 smartdns_lite prerouting6 meta l4proto udp ip6 daddr @ipv6 tproxy to ::1:${tproxy_port} mark set 1104 else echo "table_type error" return 1 fi } clear_tproxy_rules() { ip rule del fwmark 1104 > /dev/null 2>&1 ip route flush table 981 > /dev/null 2>&1 iptables -t mangle -D PREROUTING -j SMARTDNS_LITE > /dev/null 2>&1 iptables -t mangle -F SMARTDNS_LITE > /dev/null 2>&1 iptables -t mangle -X SMARTDNS_LITE > /dev/null 2>&1 ip6tables -t mangle -D PREROUTING -j SMARTDNS_LITE > /dev/null 2>&1 ip6tables -t mangle -F SMARTDNS_LITE > /dev/null 2>&1 ip6tables -t mangle -X SMARTDNS_LITE > /dev/null 2>&1 nft delete table ip smartdns_lite > /dev/null 2>&1 nft delete table ip6 smartdns_lite > /dev/null 2>&1 } clear_rules() { clear_tproxy_rules } load_parental_control_rules() { local section="$1" local adblock_set_name="$2" local block_domain_set_file="" local client_set_name="pc-client-address-$section" local block_set_name="pc-block-domain-$section" local server_options="-e" config_get_bool pc_enabled "$section" "pc_enabled" "0" [ "$pc_enabled" != "1" ] && return conf_append "group-begin" "parental-control-${section}" config_get pc_client_addr_file "$section" "pc_client_addr_file" "" [ -e "$pc_client_addr_file" ] && { conf_append "ip-set" "-name ${client_set_name} -file '$pc_client_addr_file'" conf_append "group-match" "-client-ip ip-set:${client_set_name}" } config_list_foreach "$section" "pc_client_addr" client_rule_addr_append config_list_foreach "$section" "pc_servers" servers_append config_get pc_block_file "$section" "pc_block_file" "" [ -e "$pc_block_file" ] && { conf_append "domain-set" "-name ${block_set_name} -file '$pc_block_file'" conf_append "domain-rules" "/domain-set:${block_set_name}/ -address #" } [ ! -z "$adblock_set_name" ] && { conf_append "domain-rules" "/domain-set:${adblock_set_name}/ -address #" } conf_append "group-end" } load_domain_rules() { local section="$1" local domain_set_args="" local domain_set_name="rules-domain-set-$section" local domain_rule_name="rules-domain-group-$section" local as_group=0; local qtype_soa_list="" local server_options="" clear_tproxy_rules config_get_bool rules_enabled "$section" "rules_enabled" "0" [ "$rules_enabled" != "1" ] && return config_list_foreach "$section" "rules_servers" servers_append config_get rules_domain_file "$section" "rules_domain_file" "" [ -e "$rules_domain_file" ] && { conf_append "group-begin" "${domain_rule_name}" conf_append "domain-set" "-name ${domain_set_name} -file '$rules_domain_file'" conf_append "group-match" "-domain domain-set:${domain_set_name}" conf_append "force-qtype-SOA" "-" server_options="-e" as_group="1" } config_get rules_speed_check_mode "$section" "rules_speed_check_mode" "" [ ! -z "$rules_speed_check_mode" ] && conf_append "speed-check-mode" "$rules_speed_check_mode" config_get rules_force_aaaa_soa "$section" "rules_force_aaaa_soa" "0" [ "$rules_force_aaaa_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 28" config_get rules_force_https_soa "$section" "rules_force_https_soa" "1" [ "$rules_force_https_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 65" [ ! -z "$qtype_soa_list" ] && conf_append "force-qtype-SOA" "$qtype_soa_list" config_get_bool use_internal_rules "$section" "use_internal_rules" "0" [ "$use_internal_rules" = "1" ] && { config_get tproxy_server_port "$section" "tproxy_server_port" "" [ ! -z "$tproxy_server_port" ] && { which nft > /dev/null 2>&1 if [ "$?" = "0" ]; then table_type="nftable" conf_append "nftset" "#4:ip#smartdns_lite#ipv4" conf_append "nftset" "#6:ip6#smartdns_lite#ipv6" else conf_append "ipset" "SMARTDNS_LITE" table_type="iptable" fi setup_tproxy_rules "$tproxy_server_port" "$table_type" } } || { config_get ipset_name "$section" "ipset_name" "" [ -z "$ipset_name" ] || conf_append "ipset" "$ipset_name" config_get nftset_name "$section" "nftset_name" "" [ -z "$nftset_name" ] || conf_append "nftset" "$nftset_name" } [ "$as_group" = "1" ] && { conf_append "group-end" } } cloudflare_cdn_alias() { conf_append "ip-alias" "$1 ip-set:$ipset_set_name" } load_cloudflare_cdn_accelerate() { local section="$1" local ipset_set_name="cloudflare-ip-set-$section" config_get_bool cloudflare_enabled "$section" "cloudflare_enabled" "0" [ "$cloudflare_enabled" != "1" ] && return config_get cloudflare_cdn_ip_file "$section" "cloudflare_cdn_ip_file" "" [ ! -e "$cloudflare_cdn_ip_file" ] && return conf_append "ip-set" "-name ${ipset_set_name} -file '$cloudflare_cdn_ip_file'" config_list_foreach "$section" "cloudflare_ip_alias" cloudflare_cdn_alias } unload_service() { : } load_service() { local section="$1" args="" local device="" local adblock_set_name="" local auto_set_dnsmasq="0" mkdir -p $SMARTDNS_VAR_CONF_DIR rm -f $SMARTDNS_CONF_TMP config_get_bool enabled "$section" "enabled" '0' [ "$enabled" != "1" ] && { uci -q set smartdns.@smartdns[0].enabled="0" uci -q del_list smartdns.@smartdns[0].conf_files="$SMARTDNS_CONF" uci commit smartdns clear_tproxy_rules /etc/init.d/smartdns reload return } config_get port "$section" "port" "53" config_get server_mode "$section" "server_mode" "main" [ "$server_mode" = "main" ] && { port="53" } [ "$server_mode" = "dnsmasq_upstream" ] && { auto_set_dnsmasq="1" } config_list_foreach "$section" "servers" servers_append config_get ad_block_file "$section" "ad_block_file" "" [ -e "$ad_block_file" ] && { adblock_set_name="adblock-block-$section" conf_append "domain-set" "-name ${adblock_set_name} -file '$ad_block_file'" conf_append "domain-rules" "/domain-set:${adblock_set_name}/ -address #" } load_cloudflare_cdn_accelerate "$section" load_parental_control_rules "$section" "$adblock_set_name" load_domain_rules "$section" uci -q set smartdns.@smartdns[0].enabled="1" uci -q set smartdns.@smartdns[0].port="$port" uci -q set smartdns.@smartdns[0].auto_set_dnsmasq="$auto_set_dnsmasq" uci -q del_list smartdns.@smartdns[0].conf_files="$SMARTDNS_CONF" uci -q add_list smartdns.@smartdns[0].conf_files="$SMARTDNS_CONF" touch $SMARTDNS_CONF_TMP mv $SMARTDNS_CONF_TMP $SMARTDNS_CONF uci commit smartdns /etc/init.d/smartdns reload } service_triggers() { procd_add_reload_trigger smartdns-lite } service_stopped() { config_load "smartdns-lite" config_foreach unload_service "smartdns-lite" } start_service() { config_load "smartdns-lite" config_foreach load_service "smartdns-lite" } reload_service() { stop start }