#!/bin/sh /etc/rc.common START=99 STOP=10 USE_PROCD=1 . "$IPKG_INSTROOT/lib/functions/network.sh" . "$IPKG_INSTROOT/etc/mihomo/scripts/constants.sh" start_service() { # clear log clear_all_log # load config config_load mihomo # check if enabled local enabled config_get_bool enabled "config" "enabled" 0 if [ "$enabled" == 0 ]; then log "App is disabled." log "Exiting..." return fi log "App is enabled." log "Starting..." # get config ## app config local scheduled_restart cron_expression profile mixin test_profile fast_reload config_get_bool scheduled_restart "config" "scheduled_restart" 0 config_get cron_expression "config" "cron_expression" config_get profile "config" "profile" config_get_bool mixin "config" "mixin" 0 config_get_bool test_profile "config" "test_profile" 0 config_get_bool fast_reload "config" "fast_reload" 0 ## proxy config ### transparent proxy local transparent_proxy tcp_transparent_proxy_mode udp_transparent_proxy_mode ipv4_dns_hijack ipv6_dns_hijack ipv4_proxy ipv6_proxy router_proxy lan_proxy config_get_bool transparent_proxy "proxy" "transparent_proxy" 0 config_get tcp_transparent_proxy_mode "proxy" "tcp_transparent_proxy_mode" "tproxy" config_get udp_transparent_proxy_mode "proxy" "udp_transparent_proxy_mode" "tproxy" config_get_bool ipv4_dns_hijack "proxy" "ipv4_dns_hijack" 0 config_get_bool ipv6_dns_hijack "proxy" "ipv6_dns_hijack" 0 config_get_bool ipv4_proxy "proxy" "ipv4_proxy" 0 config_get_bool ipv6_proxy "proxy" "ipv6_proxy" 0 config_get_bool router_proxy "proxy" "router_proxy" 0 config_get_bool lan_proxy "proxy" "lan_proxy" 0 ### access control local access_control_mode bypass_china_mainland_ip acl_tcp_dport acl_udp_dport config_get access_control_mode "proxy" "access_control_mode" config_get_bool bypass_china_mainland_ip "proxy" "bypass_china_mainland_ip" 0 config_get acl_tcp_dport "proxy" "acl_tcp_dport" "0-65535" config_get acl_udp_dport "proxy" "acl_udp_dport" "0-65535" ## mixin config ### general local mode match_process outbound_interface ipv6 tcp_keep_alive_idle tcp_keep_alive_interval log_level config_get mode "mixin" "mode" "rule" config_get match_process "mixin" "match_process" "off" config_get outbound_interface "mixin" "outbound_interface" config_get_bool ipv6 "mixin" "ipv6" 0 config_get tcp_keep_alive_idle "mixin" "tcp_keep_alive_idle" 600 config_get tcp_keep_alive_interval "mixin" "tcp_keep_alive_interval" 15 config_get log_level "mixin" "log_level" "info" ### external control local ui_name ui_url api_port api_secret selection_cache config_get ui_name "mixin" "ui_name" config_get ui_url "mixin" "ui_url" config_get api_port "mixin" "api_port" "9090" config_get api_secret "mixin" "api_secret" "666666" config_get_bool selection_cache "mixin" "selection_cache" 0 ### inbound local allow_lan http_port socks_port mixed_port redir_port tproxy_port authentication config_get_bool allow_lan "mixin" "allow_lan" 0 config_get http_port "mixin" "http_port" "8080" config_get socks_port "mixin" "socks_port" "1080" config_get mixed_port "mixin" "mixed_port" "7890" config_get redir_port "mixin" "redir_port" "7891" config_get tproxy_port "mixin" "tproxy_port" "7892" config_get_bool authentication "mixin" "authentication" 0 ### tun local tun_stack tun_mtu tun_gso tun_gso_max_size tun_endpoint_independent_nat config_get tun_stack "mixin" "tun_stack" "system" config_get tun_mtu "mixin" "tun_mtu" "9000" config_get_bool tun_gso "mixin" "tun_gso" 0 config_get tun_gso_max_size "mixin" "tun_gso_max_size" "65536" config_get_bool tun_endpoint_independent_nat "mixin" "tun_endpoint_independent_nat" 0 ### dns local dns_port dns_mode fake_ip_range fake_ip_filter fake_ip_filter_mode fake_ip_cache dns_respect_rules dns_ipv6 dns_system_hosts dns_hosts hosts dns_nameserver dns_nameserver_policy config_get dns_port "mixin" "dns_port" "1053" config_get dns_mode "mixin" "dns_mode" "redir-host" config_get fake_ip_range "mixin" "fake_ip_range" "198.18.0.1/16" config_get_bool fake_ip_filter "mixin" "fake_ip_filter" 0 config_get fake_ip_filter_mode "mixin" "fake_ip_filter_mode" "blacklist" config_get_bool fake_ip_cache "mixin" "fake_ip_cache" 0 config_get_bool dns_respect_rules "mixin" "dns_respect_rules" 0 config_get_bool dns_ipv6 "mixin" "dns_ipv6" 0 config_get_bool dns_system_hosts "mixin" "dns_system_hosts" 0 config_get_bool dns_hosts "mixin" "dns_hosts" 0 config_get_bool hosts "mixin" "hosts" 0 config_get_bool dns_nameserver "mixin" "dns_nameserver" 0 config_get_bool dns_nameserver_policy "mixin" "dns_nameserver_policy" 0 ### geox local geoip_format geodata_loader geosite_url geoip_mmdb_url geoip_dat_url geoip_asn_url geox_auto_update geox_update_interval config_get geoip_format "mixin" "geoip_format" "mmdb" config_get geodata_loader "mixin" "geodata_loader" "memconservative" config_get geosite_url "mixin" "geosite_url" config_get geoip_mmdb_url "mixin" "geoip_mmdb_url" config_get geoip_dat_url "mixin" "geoip_dat_url" config_get geoip_asn_url "mixin" "geoip_asn_url" config_get_bool geox_auto_update "mixin" "geox_auto_update" 0 config_get geox_update_interval "mixin" "geox_update_interval" "24" # prepare local tproxy_enable; tproxy_enable=0 if [[ "$tcp_transparent_proxy_mode" == "tproxy" || "$udp_transparent_proxy_mode" == "tproxy" ]]; then tproxy_enable=1 fi local tun_enable; tun_enable=0 if [[ "$tcp_transparent_proxy_mode" == "tun" || "$udp_transparent_proxy_mode" == "tun" ]]; then tun_enable=1 fi # get profile if [[ "$profile" == "file:"* ]]; then local profile_name; profile_name=$(basename "${profile/file:/}") cp -f "$PROFILES_DIR/$profile_name" "$RUN_PROFILE_PATH" log "Use Profile: $profile_name" elif [[ "$profile" == "subscription:"* ]]; then local subscription_section; subscription_section="${profile/subscription:/}" local subscription_name subscription_url subscription_user_agent config_get subscription_name "$subscription_section" "name" config_get subscription_url "$subscription_section" "url" config_get subscription_user_agent "$subscription_section" "user_agent" curl -s --connect-timeout 15 --retry 3 -o "$RUN_PROFILE_PATH" -L -H "User-Agent: $subscription_user_agent" "$subscription_url" if [ "$?" != 0 ]; then log "Subscription download failed." log "Exiting..." return fi log "Use Subscription: $subscription_name" else return fi # mixin if [ "$mixin" == 0 ]; then log "Mixin is disabled, only mixin neccesary config." # do mixin log_level="$log_level" ipv6="$ipv6" \ ui_path="ui" ui_name="$ui_name" ui_url="$ui_url" api_listen="0.0.0.0:$api_port" api_secret="$api_secret" \ http_port="$http_port" socks_port="$socks_port" mixed_port="$mixed_port" redir_port="$redir_port" tproxy_port="$tproxy_port" \ tun_enable="$tun_enable" tun_stack="$tun_stack" tun_device="$TUN_DEVICE" tun_mtu="$tun_mtu" tun_gso="$tun_gso" tun_gso_max_size="$tun_gso_max_size" tun_endpoint_independent_nat="$tun_endpoint_independent_nat" \ dns_enable="true" dns_listen="0.0.0.0:$dns_port" \ yq -M -i ' .log-level = env(log_level) | .ipv6 = env(ipv6) == 1 | .external-ui = env(ui_path) | .external-ui-name = env(ui_name) | .external-ui-url = env(ui_url) | .external-controller = env(api_listen) | .secret = env(api_secret) | .port = env(http_port) | .socks-port = env(socks_port) | .mixed-port = env(mixed_port) | .redir-port = env(redir_port) | .tproxy-port = env(tproxy_port) | .tun.enable = env(tun_enable) == 1 | .tun.stack = env(tun_stack) | .tun.device = env(tun_device) | .tun.mtu = env(tun_mtu) | .tun.gso = env(tun_gso) == 1 | .tun.gso-max-size = env(tun_gso_max_size) | .tun.endpoint-independent-nat = env(tun_endpoint_independent_nat) == 1 | .dns.enable = env(dns_enable) | .dns.listen = env(dns_listen) ' "$RUN_PROFILE_PATH" else log "Mixin is enabled, mixin all config." # do mixin log_level="$log_level" mode="$mode" match_process="$match_process" tcp_keep_alive_idle="$tcp_keep_alive_idle" tcp_keep_alive_interval="$tcp_keep_alive_interval" ipv6="$ipv6" \ ui_path="ui" ui_name="$ui_name" ui_url="$ui_url" api_listen="0.0.0.0:$api_port" api_secret="$api_secret" selection_cache="$selection_cache" \ allow_lan="$allow_lan" http_port="$http_port" socks_port="$socks_port" mixed_port="$mixed_port" redir_port="$redir_port" tproxy_port="$tproxy_port" \ tun_enable="$tun_enable" tun_stack="$tun_stack" tun_device="$TUN_DEVICE" tun_mtu="$tun_mtu" tun_gso="$tun_gso" tun_gso_max_size="$tun_gso_max_size" tun_endpoint_independent_nat="$tun_endpoint_independent_nat" \ dns_enable="true" dns_listen="0.0.0.0:$dns_port" dns_mode="$dns_mode" fake_ip_range="$fake_ip_range" fake_ip_cache="$fake_ip_cache" \ dns_respect_rules="$dns_respect_rules" dns_ipv6="$dns_ipv6" dns_system_hosts="$dns_system_hosts" dns_hosts="$dns_hosts" \ geoip_format="$geoip_format" geodata_loader="$geodata_loader" geosite_url="$geosite_url" geoip_mmdb_url="$geoip_mmdb_url" geoip_dat_url="$geoip_dat_url" geoip_asn_url="$geoip_asn_url" \ geox_auto_update="$geox_auto_update" geox_update_interval="$geox_update_interval" \ yq -M -i ' .log-level = env(log_level) | .mode = env(mode) | .find-process-mode = env(match_process) | .keep-alive-idle = env(tcp_keep_alive_idle) | .keep-alive-interval = env(tcp_keep_alive_interval) | .ipv6 = env(ipv6) == 1 | .external-ui = env(ui_path) | .external-ui-name = env(ui_name) | .external-ui-url = env(ui_url) | .external-controller = env(api_listen) | .secret = env(api_secret) | .profile.store-selected = env(selection_cache) == 1 | .allow-lan = env(allow_lan) == 1 | .port = env(http_port) | .socks-port = env(socks_port) | .mixed-port = env(mixed_port) | .redir-port = env(redir_port) | .tproxy-port = env(tproxy_port) | .tun.enable = env(tun_enable) == 1 | .tun.stack = env(tun_stack) | .tun.device = env(tun_device) | .tun.mtu = env(tun_mtu) | .tun.gso = env(tun_gso) == 1 | .tun.gso-max-size = env(tun_gso_max_size) | .tun.endpoint-independent-nat = env(tun_endpoint_independent_nat) == 1 | .dns.enable = env(dns_enable) | .dns.listen = env(dns_listen) | .dns.enhanced-mode = env(dns_mode) | .dns.fake-ip-range = env(fake_ip_range) | .profile.store-fake-ip = env(fake_ip_cache) == 1 | .dns.respect-rules = env(dns_respect_rules) == 1 | .dns.ipv6 = env(dns_ipv6) == 1 | .dns.use-system-hosts = env(dns_system_hosts) == 1 | .dns.use-hosts = env(dns_hosts) == 1 | .geodata-mode = env(geoip_format) == "dat" | .geodata-loader = env(geodata_loader) | .geox-url.geosite = env(geosite_url) | .geox-url.mmdb = env(geoip_mmdb_url) | .geox-url.geoip = env(geoip_dat_url) | .geox-url.asn = env(geoip_asn_url) | .geo-auto-update = env(geox_auto_update) == 1 | .geo-update-interval = env(geox_update_interval) ' "$RUN_PROFILE_PATH" if [ "$authentication" == 1 ]; then yq -M -i 'del(.authentication)' "$RUN_PROFILE_PATH" config_foreach mixin_authentications "authentication" fi if [ "$fake_ip_filter" == 1 ]; then fake_ip_filter_mode="$fake_ip_filter_mode" \ yq -M -i 'del(.dns.fake-ip-filter) | .dns.fake-ip-filter-mode = env(fake_ip_filter_mode)' "$RUN_PROFILE_PATH" config_list_foreach "mixin" "fake_ip_filters" mixin_fake_ip_filters fi if [ "$hosts" == 1 ]; then yq -M -i 'del(.hosts)' "$RUN_PROFILE_PATH" config_foreach mixin_hosts "host" fi if [ "$dns_nameserver" == 1 ]; then yq -M -i 'del(.dns.default-nameserver) | del(.dns.proxy-server-nameserver) | del(.dns.nameserver) | del(.dns.fallback)' "$RUN_PROFILE_PATH" config_foreach mixin_nameservers "nameserver" fi if [ "$dns_nameserver_policy" == 1 ]; then yq -M -i 'del(.dns.nameserver-policy)' "$RUN_PROFILE_PATH" config_foreach mixin_nameserver_policies "nameserver_policy" fi # mixin file if [ -s "$MIXIN_FILE_PATH" ]; then yq ea -M -i '. as $item ireduce ({}; . * $item ) | ... comments=""' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH" fi fi yq -M -i 'del (.bind-address)' "$RUN_PROFILE_PATH" if [ "$tun_enable" == 1 ]; then yq -M -i '.tun.auto-route = false | .tun.auto-redirect = false | .tun.auto-detect-interface = false | .tun.dns-hijack = []' "$RUN_PROFILE_PATH" fi if [ -n "$outbound_interface" ]; then local outbound_device network_get_device outbound_device "$outbound_interface" if [ -n "$outbound_device" ]; then outbound_device="$outbound_device" yq -M -i '.interface-name = env(outbound_device)' "$RUN_PROFILE_PATH" fi fi # test profile if [ "$test_profile" == 1 ]; then log "Profile testing..." if ($PROG -d "$RUN_DIR" -t >> "$RUN_CORE_LOG_PATH" 2>&1); then log "Profile test passed!" else log "Profile test failed!" log "Exiting..." return fi fi # start core log "Start Core" procd_open_instance mihomo procd_set_param command /bin/sh -c "$PROG -d $RUN_DIR >> $RUN_CORE_LOG_PATH 2>&1" procd_set_param file "$RUN_PROFILE_PATH" if [ "$fast_reload" == 1 ]; then procd_set_param reload_signal HUP fi procd_set_param respawn procd_set_param user "$MIHOMO_USER" procd_set_param group "$MIHOMO_GROUP" procd_add_jail mihomo requirejail procfs procd_add_jail_mount "$PROG" /etc/TZ /etc/localtime /etc/hosts /etc/ssl/certs procd_add_jail_mount_rw "$RUN_DIR" /dev/net procd_set_param capabilities /etc/capabilities/mihomo.json procd_set_param no_new_privs 1 procd_close_instance # transparent proxy if [ "$transparent_proxy" == 1 ]; then log "Transparent Proxy is enabled." log "Transparent Proxy: Start hijack." # prepare if [ "$tproxy_enable" == 1 ]; then if [ "$ipv4_proxy" == 1 ]; then ip route add local default dev lo table "$TPROXY_ROUTE_TABLE" fi if [ "$ipv6_proxy" == 1 ]; then ip -6 route add local default dev lo table "$TPROXY_ROUTE_TABLE" fi fi if [ "$tun_enable" == 1 ]; then ip tuntap add dev "$TUN_DEVICE" mode tun vnet_hdr ip link set "$TUN_DEVICE" up if [ "$ipv4_proxy" == 1 ]; then ip route add unicast default dev $TUN_DEVICE table "$TUN_ROUTE_TABLE" fi if [ "$ipv6_proxy" == 1 ]; then ip -6 route add unicast default dev $TUN_DEVICE table "$TUN_ROUTE_TABLE" fi $TUN_SH fi local tcp_route_table if [ "$tcp_transparent_proxy_mode" == "tproxy" ]; then tcp_route_table="$TPROXY_ROUTE_TABLE" elif [ "$tcp_transparent_proxy_mode" == "tun" ]; then tcp_route_table="$TUN_ROUTE_TABLE" fi if [ -n "$tcp_route_table" ]; then if [ "$ipv4_proxy" == 1 ]; then ip rule add pref "$TCP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto tcp table "$tcp_route_table" fi if [ "$ipv6_proxy" == 1 ]; then ip -6 rule add pref "$TCP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto tcp table "$tcp_route_table" fi fi local udp_route_table if [ "$udp_transparent_proxy_mode" == "tproxy" ]; then udp_route_table="$TPROXY_ROUTE_TABLE" elif [ "$udp_transparent_proxy_mode" == "tun" ]; then udp_route_table="$TUN_ROUTE_TABLE" fi if [ -n "$udp_route_table" ]; then if [ "$ipv4_proxy" == 1 ]; then ip rule add pref "$UDP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto udp table "$udp_route_table" fi if [ "$ipv6_proxy" == 1 ]; then ip -6 rule add pref "$UDP_RULE_PREF" fwmark "$FW_MARK/$FW_MARK_MASK" ipproto udp table "$udp_route_table" fi fi nft -f "$HIJACK_NFT" -D FW_MARK="$FW_MARK" -D FW_MARK_MASK="$FW_MARK_MASK" -D MIHOMO_USER="$MIHOMO_USER" -D TUN_DEVICE="$TUN_DEVICE" -D DNS_PORT="$dns_port" -D REDIR_PORT="$redir_port" -D TPROXY_PORT="$tproxy_port" nft -f "$RESERVED_IP_NFT" nft -f "$RESERVED_IP6_NFT" nft add element inet "$FW_TABLE" fake_ip \{ "$fake_ip_range" \} # dns hijack if [ "$ipv4_dns_hijack" == 1 ]; then log "Transparent Proxy: IPv4 DNS Hijack is enabled, IPv4 dns request will redirect to the core." nft add element inet "$FW_TABLE" dns_hijack_nfproto \{ ipv4 \} fi if [ "$ipv6_dns_hijack" == 1 ]; then log "Transparent Proxy: IPv6 DNS Hijack is enabled, IPv6 dns request will redirect to the core." nft add element inet "$FW_TABLE" dns_hijack_nfproto \{ ipv6 \} fi # proxy if [ "$ipv4_proxy" == 1 ]; then log "Transparent Proxy: IPv4 Proxy is enabled, set proxy for IPv4 traffic." nft add element inet "$FW_TABLE" proxy_nfproto \{ ipv4 \} fi if [ "$ipv6_proxy" == 1 ]; then log "Transparent Proxy: IPv6 Proxy is enabled, set proxy for IPv6 traffic." nft add element inet "$FW_TABLE" proxy_nfproto \{ ipv6 \} fi # bypass china mainland ip if [ "$bypass_china_mainland_ip" == 1 ]; then log "Transparent Proxy: Bypass china mainland ip is enabled." if [ "$ipv4_proxy" == 1 ]; then nft -f "$GEOIP_CN_NFT" fi if [ "$ipv6_proxy" == 1 ]; then nft -f "$GEOIP6_CN_NFT" fi fi # destination port to proxy log "Transparent Proxy: Destination TCP Port to Proxy: $acl_tcp_dport." log "Transparent Proxy: Destination UDP Port to Proxy: $acl_udp_dport." local acl_dport for acl_dport in $acl_tcp_dport; do nft add element inet "$FW_TABLE" acl_dport \{ "tcp" . "$acl_dport" \} done for acl_dport in $acl_udp_dport; do nft add element inet "$FW_TABLE" acl_dport \{ "udp" . "$acl_dport" \} done # router proxy if [ "$router_proxy" == 1 ]; then log "Transparent Proxy: Router Proxy is enabled, set proxy for router." nft insert rule inet "$FW_TABLE" nat_output jump router_dns_hijack if [ "$tcp_transparent_proxy_mode" == "redirect" ]; then nft add rule inet "$FW_TABLE" nat_output meta l4proto tcp jump router_redirect else nft add rule inet "$FW_TABLE" mangle_output meta l4proto tcp jump router_reroute fi nft add rule inet "$FW_TABLE" mangle_output meta l4proto udp jump router_reroute fi # lan proxy if [ "$lan_proxy" == 1 ]; then log "Transparent Proxy: Lan Proxy is enabled, set proxy for lan." # access control if [ "$access_control_mode" == "all" ]; then log "Transparent Proxy: Access Control is using all mode, set proxy for all client." elif [ "$access_control_mode" == "allow" ]; then log "Transparent Proxy: Access Control is using allow mode, set proxy for client which is in acl." elif [ "$access_control_mode" == "block" ]; then log "Transparent Proxy: Access Control is using block mode, set proxy for client which is not in acl." fi config_list_foreach "proxy" "acl_ip" add_acl_ip config_list_foreach "proxy" "acl_ip6" add_acl_ip6 config_list_foreach "proxy" "acl_mac" add_acl_mac nft insert rule inet "$FW_TABLE" dstnat jump "${access_control_mode}_dns_hijack" if [ "$tcp_transparent_proxy_mode" == "redirect" ]; then nft add rule inet "$FW_TABLE" dstnat meta l4proto tcp jump "${access_control_mode}_redirect" else nft add rule inet "$FW_TABLE" mangle_prerouting meta l4proto tcp jump "${access_control_mode}_${tcp_transparent_proxy_mode}" fi nft add rule inet "$FW_TABLE" mangle_prerouting meta l4proto udp jump "${access_control_mode}_${udp_transparent_proxy_mode}" fi fi # cron if [[ "$scheduled_restart" == 1 && -n "$cron_expression" ]]; then log "Add crontab for scheduled restart." echo "$cron_expression /etc/init.d/mihomo restart #mihomo" >> "/etc/crontabs/root" /etc/init.d/cron restart fi log "Start Successful!" } service_stopped() { cleanup } reload_service() { cleanup start } service_triggers() { procd_add_reload_trigger "mihomo" } cleanup() { # delete routing policy ip rule del ipproto tcp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip rule del ipproto udp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip rule del ipproto tcp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip rule del ipproto udp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip -6 rule del ipproto tcp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip -6 rule del ipproto udp table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip -6 rule del ipproto tcp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip -6 rule del ipproto udp table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 # delete routing table ip route flush table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip route flush table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 ip -6 route flush table "$TPROXY_ROUTE_TABLE" > /dev/null 2>&1 ip -6 route flush table "$TUN_ROUTE_TABLE" > /dev/null 2>&1 # delete tun ip link set "$TUN_DEVICE" down > /dev/null 2>&1 ip tuntap del dev "$TUN_DEVICE" mode tun > /dev/null 2>&1 # delete hijack nft delete table inet "$FW_TABLE" > /dev/null 2>&1 local handles handle handles=$(nft --json list table inet fw4 | yq '.nftables[] | select(has("rule")) | .rule | select(.family == "inet" and .table == "fw4" and .chain == "input" and .expr[0].match.right == "tun") | .handle') for handle in $handles; do nft delete rule inet fw4 input handle "$handle" done handles=$(nft --json list table inet fw4 | yq '.nftables[] | select(has("rule")) | .rule | select(.family == "inet" and .table == "fw4" and .chain == "forward" and .expr[0].match.right == "tun") | .handle') for handle in $handles; do nft delete rule inet fw4 forward handle "$handle" done # delete cron sed -i '/#mihomo/d' "/etc/crontabs/root" > /dev/null 2>&1 /etc/init.d/cron restart } log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$RUN_APP_LOG_PATH" } clear_all_log() { echo -n > "$RUN_APP_LOG_PATH" echo -n > "$RUN_CORE_LOG_PATH" } mixin_authentications() { local section="$1" local enabled username password config_get_bool enabled "$section" "enabled" 0 config_get username "$section" "username" config_get password "$section" "password" if [ "$enabled" == 0 ]; then return fi authentication="$username:$password" yq -M -i '.authentication += [env(authentication)]' "$RUN_PROFILE_PATH" } mixin_fake_ip_filters() { domain_name="$1" yq -M -i '.dns.fake-ip-filter += [env(domain_name)]' "$RUN_PROFILE_PATH" } mixin_hosts() { local section="$1" local enabled domain_name config_get_bool enabled "$section" "enabled" 0 config_get domain_name "$section" "domain_name" if [ "$enabled" == 0 ]; then return fi config_list_foreach "$section" "ip" mixin_host "$domain_name" } mixin_host() { ip="$1" domain_name="$2" yq -M -i '.hosts.[env(domain_name)] += [env(ip)]' "$RUN_PROFILE_PATH" } mixin_nameservers() { local section="$1" local enabled type config_get_bool enabled "$section" "enabled" 0 config_get type "$section" "type" if [ "$enabled" == 0 ]; then return fi config_list_foreach "$section" "nameserver" mixin_nameserver "$type" } mixin_nameserver() { nameserver="$1" type="$2" yq -M -i '.dns.[env(type)] += [env(nameserver)]' "$RUN_PROFILE_PATH" } mixin_nameserver_policies() { local section="$1" local enabled matcher config_get_bool enabled "$section" "enabled" 0 config_get matcher "$section" "matcher" if [ "$enabled" == 0 ]; then return fi config_list_foreach "$section" "nameserver" mixin_nameserver_policy "$matcher" } mixin_nameserver_policy() { nameserver="$1" matcher="$2" yq -M -i '.dns.nameserver-policy.[env(matcher)] += [env(nameserver)]' "$RUN_PROFILE_PATH" } add_acl_ip() { nft add element inet "$FW_TABLE" acl_ip \{ "$1" \} } add_acl_ip6() { nft add element inet "$FW_TABLE" acl_ip6 \{ "$1" \} } add_acl_mac() { nft add element inet "$FW_TABLE" acl_mac \{ "$1" \} }