#!/usr/bin/utpl -S {%- import { readfile } from 'fs'; import { cursor } from 'uci'; import { isEmpty } from '/etc/homeproxy/scripts/homeproxy.uc'; const fw4 = require('fw4'); function array_to_nftarr(array) { if (type(array) !== 'array') return null; return `{ ${join(', ', uniq(array))} }`; } function resolve_ipv6(str) { if (isEmpty(str)) return null; let ipv6 = fw4.parse_subnet(str)?.[0]; if (!ipv6 || ipv6.family !== 6) return null; if (ipv6.bits > -1) return `${ipv6.addr}/${ipv6.bits}`; else return `& ${ipv6.mask} == ${ipv6.addr}`; } function resolve_mark(str) { if (isEmpty(str)) return null; let mark = fw4.parse_mark(str); if (isEmpty(mark)) return null; if (mark.mask === 0xffffffff) return fw4.hex(mark.mark); else if (mark.mark === 0) return `mark and ${fw4.hex(~mark.mask & 0xffffffff)}`; else if (mark.mark === mark.mask) return `mark or ${fw4.hex(mark.mark)}`; else if (mark.mask === 0) return `mark xor ${fw4.hex(mark.mark)}`; else return `mark and ${fw4.hex(~mark.mask & 0xffffffff)} xor ${fw4.hex(mark.mark)}`; } /* Misc config */ const resources_dir = '/etc/homeproxy/resources'; /* UCI config start */ const cfgname = 'homeproxy'; const uci = cursor(); uci.load(cfgname); const routing_mode = uci.get(cfgname, 'config', 'routing_mode') || 'proxy_banned_ru'; let outbound_node, outbound_udp_node; if (routing_mode !== 'custom') { outbound_node = uci.get(cfgname, 'config', 'main_node') || 'nil'; outbound_udp_node = uci.get(cfgname, 'config', 'main_udp_node') || 'nil'; } else { outbound_node = uci.get(cfgname, 'routing', 'default_outbound') || 'nil'; } let routing_port = uci.get(cfgname, 'config', 'routing_port'); if (routing_port === 'common') routing_port = uci.get(cfgname, 'infra', 'common_port') || '22,53,80,143,443,465,587,853,873,993,995,8080,8443,9418'; const proxy_mode = uci.get(cfgname, 'config', 'proxy_mode') || 'redirect_tproxy', ipv6_support = uci.get(cfgname, 'config', 'ipv6_support') || '0'; let self_mark, redirect_port, tproxy_port, tproxy_mark, tun_name, tun_mark; /* ByeDPI runs as root (needed for TCP_MD5SIG etc.) but under a dedicated group, so its * egress can be excluded from the redirect by socket group (skgid) to break the proxy * loop — ciadpi has no fwmark option, and root traffic can't be told apart by skuid. */ const byedpi_enabled = uci.get(cfgname, 'config', 'byedpi_enabled') || '0'; const byedpi_gid = uci.get(cfgname, 'infra', 'byedpi_gid') || '8181'; /* zapret: sing-box's `zapret-out` direct outbound stamps egress with zapret_mark (a * routing_mark that OVERRIDES default_mark). That mark must (a) escape the redirect loop * like self_mark does, and (b) be steered into NFQUEUE so nfqws can desync the handshake. * nfqws reinjects its fake packets carrying its own desync mark (0x40000000) — those must * also escape the redirect, and must NOT be re-queued. */ const zapret_enabled = uci.get(cfgname, 'config', 'zapret_enabled') || '0'; const zapret_mark = uci.get(cfgname, 'config', 'zapret_mark') || '110'; const zapret_qnum = uci.get(cfgname, 'config', 'zapret_qnum') || '200'; const zapret_desync_mark = '0x40000000'; /* nfqws DESYNC_MARK (its reinjected fakes) */ if (match(proxy_mode, /redirect/)) { self_mark = uci.get(cfgname, 'infra', 'self_mark') || '100'; redirect_port = uci.get(cfgname, 'infra', 'redirect_port') || '5331'; } if (match(proxy_mode, /tproxy/)) if (outbound_udp_node !== 'nil' || routing_mode === 'custom' || routing_mode === 'proxy_banned_ru') { tproxy_port = uci.get(cfgname, 'infra', 'tproxy_port') || '5332'; tproxy_mark = resolve_mark(uci.get(cfgname, 'infra', 'tproxy_mark') || '101'); } if (match(proxy_mode, /tun/)) { tun_name = uci.get(cfgname, 'infra', 'tun_name') || 'singtun0'; tun_mark = resolve_mark(uci.get(cfgname, 'infra', 'tun_mark') || '102'); } const control_options = [ "listen_interfaces", "lan_proxy_mode", "lan_direct_mac_addrs", "lan_direct_ipv4_ips", "lan_direct_ipv6_ips", "lan_proxy_mac_addrs", "lan_proxy_ipv4_ips", "lan_proxy_ipv6_ips", "lan_gaming_mode_mac_addrs", "lan_gaming_mode_ipv4_ips", "lan_gaming_mode_ipv6_ips", "lan_global_proxy_mac_addrs", "lan_global_proxy_ipv4_ips", "lan_global_proxy_ipv6_ips", "wan_proxy_ipv4_ips", "wan_proxy_ipv6_ips", "wan_direct_ipv4_ips", "wan_direct_ipv6_ips" ]; const control_info = {}; for (let i in control_options) control_info[i] = uci.get(cfgname, 'control', i); const dns_redirect = uci.get(cfgname, 'infra', 'dns_redirect') || '1'; const dns_hijacked = uci.get('dhcp', '@dnsmasq[0]', 'dns_redirect') || '0', dns_port = uci.get('dhcp', '@dnsmasq[0]', 'port') || '53'; /* UCI config end */ -%} {# Reserved addresses -#} set homeproxy_local_addr_v4 { type ipv4_addr flags interval auto-merge elements = { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.31.196.0/24, 192.52.193.0/24, 192.88.99.0/24, 192.168.0.0/16, 192.175.48.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4 } } {% if (ipv6_support === '1'): %} set homeproxy_local_addr_v6 { type ipv6_addr flags interval auto-merge elements = { ::/128, ::1/128, ::ffff:0:0/96, 100::/64, 64:ff9b::/96, 2001::/32, 2001:10::/28, 2001:20::/28, 2001:db8::/28, 2002::/16, fc00::/7, fe80::/10, ff00::/8 } } {% endif %} {# WAN ACL addresses #} set homeproxy_wan_proxy_addr_v4 { type ipv4_addr flags interval auto-merge {% if (control_info.wan_proxy_ipv4_ips): %} elements = { {{ join(', ', control_info.wan_proxy_ipv4_ips) }} } {% endif %} } {% if (ipv6_support === '1'): %} set homeproxy_wan_proxy_addr_v6 { type ipv6_addr flags interval auto-merge {% if (control_info.wan_proxy_ipv6_ips): %} elements = { {{ join(', ', control_info.wan_proxy_ipv6_ips) }} } {% endif /* wan_proxy_ipv6_ips*/ %} } {% endif /* ipv6_support */ %} set homeproxy_wan_direct_addr_v4 { type ipv4_addr flags interval auto-merge {% if (control_info.wan_direct_ipv4_ips): %} elements = { {{ join(', ', control_info.wan_direct_ipv4_ips) }} } {% endif %} } {% if (ipv6_support === '1'): %} set homeproxy_wan_direct_addr_v6 { type ipv6_addr flags interval auto-merge {% if (control_info.wan_direct_ipv6_ips): %} elements = { {{ join(', ', control_info.wan_direct_ipv6_ips) }} } {% endif /* wan_direct_ipv6_ips */ %} } {% endif /* ipv6_support */ %} {% if (routing_port): %} set homeproxy_routing_port { type inet_service flags interval auto-merge elements = { {{ join(', ', split(routing_port, ',')) }} } } {% endif %} {# DNS hijack & TCP redirect #} chain dstnat { {% if ((dns_redirect === '1') && (dns_hijacked !== '1')): %} {% if (control_info.listen_interfaces): %} meta iifname {{ array_to_nftarr(control_info.listen_interfaces) }} {%- endif /* listen_interfaces */ %} meta nfproto { ipv4, ipv6 } udp dport 53 counter redirect to :{{ dns_port }} comment "!{{ cfgname }}: DNS hijack" {% endif /* dns_hijacked */ %} {% if (match(proxy_mode, /redirect/)): %} meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto tcp jump homeproxy_redirect_lanac {% endif /* proxy_mode */ %} } {# TCP redirect #} {% if (match(proxy_mode, /redirect/)): %} chain homeproxy_redirect_proxy { meta l4proto tcp counter redirect to :{{ redirect_port }} } chain homeproxy_redirect_proxy_port { {% if (routing_port): %} tcp dport != @homeproxy_routing_port counter return {% endif %} goto homeproxy_redirect_proxy } chain homeproxy_redirect_lanac { {% if (control_info.listen_interfaces): %} meta iifname != {{ array_to_nftarr(control_info.listen_interfaces) }} counter return {% endif %} meta mark {{ self_mark }} counter return {% if (control_info.lan_proxy_mode === 'listed_only'): %} {% if (!isEmpty(control_info.lan_proxy_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_proxy_ipv4_ips) }} counter goto homeproxy_redirect {% endif /* lan_proxy_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_proxy_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_redirect {% endfor /* lan_proxy_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_proxy_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_proxy_mac_addrs) }} counter goto homeproxy_redirect {% endif /* lan_proxy_mac_addrs */ %} {% elif (control_info.lan_proxy_mode === 'except_listed'): %} {% if (!isEmpty(control_info.lan_direct_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_direct_ipv4_ips) }} counter return {% endif /* lan_direct_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_direct_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter return {% endfor /* lan_direct_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_direct_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_direct_mac_addrs) }} counter return {% endif /* lan_direct_mac_addrs */ %} {% endif /* lan_proxy_mode */ %} {% if (control_info.lan_proxy_mode !== 'listed_only'): %} counter goto homeproxy_redirect {% endif %} } chain homeproxy_redirect { meta mark {{ self_mark }} counter return {% if (zapret_enabled === '1'): %} meta mark {{ zapret_mark }} counter return meta mark and {{ zapret_desync_mark }} != 0 counter return {% endif /* zapret_enabled */ %} ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_redirect_proxy_port {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_redirect_proxy_port {% endif %} ip daddr @homeproxy_local_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_local_addr_v6 counter return {% endif %} {% if (routing_mode !== 'custom'): %} {% if (!isEmpty(control_info.lan_global_proxy_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_global_proxy_ipv4_ips) }} counter goto homeproxy_redirect_proxy_port {% endif /* lan_global_proxy_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_global_proxy_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_redirect_proxy_port {% endfor /* lan_global_proxy_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_global_proxy_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_global_proxy_mac_addrs) }} counter goto homeproxy_redirect_proxy_port {% endif /* lan_global_proxy_mac_addrs */ %} {% endif /* routing_mode */ %} ip daddr @homeproxy_wan_direct_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_wan_direct_addr_v6 counter return {% endif /* ipv6_support */ %} {% if (!isEmpty(control_info.lan_gaming_mode_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_gaming_mode_ipv4_ips) }} counter goto homeproxy_redirect_proxy {% endif /* lan_gaming_mode_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_gaming_mode_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_redirect_proxy {% endfor /* lan_gaming_mode_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_gaming_mode_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_gaming_mode_mac_addrs) }} counter goto homeproxy_redirect_proxy {% endif /* lan_gaming_mode_mac_addrs */ %} counter goto homeproxy_redirect_proxy_port } chain homeproxy_output_redir { type nat hook output priority filter -105; policy accept {% if (byedpi_enabled === '1'): %} meta skgid {{ byedpi_gid }} counter return {% endif %} meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto tcp jump homeproxy_redirect } {% endif %} {# NFQUEUE chain: feed ALL Zapret-marked (mark 110) flows to nfqws2 — any port, TCP and UDP — and let the strategy's own --filter-tcp/--filter-udp profiles decide what to desync (the rest passes through via `bypass`). This mirrors how a list→outbound rule routes all matching traffic: once sing-box marks a flow for zapret-out, the queue feeds it, regardless of port (so discord.media on 2053/8443, voice UDP, QUIC, etc. all work with no per-port firewall rules). `ct original packets 1-12` caps it to each flow's handshake; nfqws's reinjected fakes carry DESYNC_MARK (not mark 110) so they are never re-queued. #} {% if (zapret_enabled === '1'): %} chain homeproxy_zapret_queue { type filter hook postrouting priority mangle; policy accept; meta mark {{ zapret_mark }} meta l4proto tcp ct original packets 1-12 counter queue num {{ zapret_qnum }} bypass meta mark {{ zapret_mark }} meta l4proto udp ct original packets 1-12 counter queue num {{ zapret_qnum }} bypass } {% endif %} {# UDP tproxy #} {% if (match(proxy_mode, /tproxy/) && (outbound_udp_node !== 'nil' || routing_mode === 'custom' || routing_mode === 'proxy_banned_ru')): %} chain homeproxy_mangle_tproxy { meta l4proto udp meta mark set {{ tproxy_mark }} tproxy ip to 127.0.0.1:{{ tproxy_port }} counter accept {% if (ipv6_support === '1'): %} meta l4proto udp meta mark set {{ tproxy_mark }} tproxy ip6 to [::1]:{{ tproxy_port }} counter accept {% endif %} } chain homeproxy_mangle_tproxy_port { {% if (routing_port): %} udp dport != @homeproxy_routing_port counter return {% endif %} goto homeproxy_mangle_tproxy } chain homeproxy_mangle_mark { {% if (routing_port): %} udp dport != @homeproxy_routing_port counter return {% endif %} meta l4proto udp meta mark set {{ tproxy_mark }} counter accept } chain homeproxy_mangle_lanac { {% if (control_info.listen_interfaces): %} meta iifname != {{ array_to_nftarr(uniq([...control_info.listen_interfaces, ...['lo']])) }} counter return {% endif %} meta iifname != lo udp dport 53 counter return meta mark {{ self_mark }} counter return {% if (control_info.lan_proxy_mode === 'listed_only'): %} {% if (!isEmpty(control_info.lan_proxy_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_proxy_ipv4_ips) }} counter goto homeproxy_mangle_prerouting {% endif /* lan_proxy_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_proxy_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_prerouting {% endfor /* lan_proxy_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_proxy_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_proxy_mac_addrs) }} counter goto homeproxy_mangle_prerouting {% endif /* lan_proxy_mac_addrs */ %} {% elif (control_info.lan_proxy_mode === 'except_listed'): %} {% if (!isEmpty(control_info.lan_direct_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_direct_ipv4_ips) }} counter return {% endif /* lan_direct_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_direct_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter return {% endfor /* lan_direct_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_direct_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_direct_mac_addrs) }} counter return {% endif /* lan_direct_mac_addrs */ %} {% endif /* lan_proxy_mode */ %} {% if (control_info.lan_proxy_mode !== 'listed_only'): %} counter goto homeproxy_mangle_prerouting {% endif %} } chain homeproxy_mangle_prerouting { ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_mangle_tproxy_port {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_mangle_tproxy_port {% endif %} ip daddr @homeproxy_local_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_local_addr_v6 counter return {% endif %} {% if (routing_mode !== 'custom'): %} {% if (!isEmpty(control_info.lan_global_proxy_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_global_proxy_ipv4_ips) }} counter goto homeproxy_mangle_tproxy_port {% endif /* lan_global_proxy_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_global_proxy_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tproxy_port {% endfor /* lan_global_proxy_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_global_proxy_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_global_proxy_mac_addrs) }} counter goto homeproxy_mangle_tproxy_port {% endif /* lan_global_proxy_mac_addrs */ %} {% endif /* routing_mode */ %} ip daddr @homeproxy_wan_direct_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_wan_direct_addr_v6 counter return {% endif /* ipv6_support */ %} {% if (!isEmpty(control_info.lan_gaming_mode_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_gaming_mode_ipv4_ips) }} counter goto homeproxy_mangle_tproxy {% endif /* lan_gaming_mode_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_gaming_mode_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tproxy {% endfor /* lan_gaming_mode_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_gaming_mode_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_gaming_mode_mac_addrs) }} counter goto homeproxy_mangle_tproxy {% endif /* lan_gaming_mode_mac_addrs */ %} counter goto homeproxy_mangle_tproxy_port } chain homeproxy_mangle_output { {% if (byedpi_enabled === '1'): %} meta skgid {{ byedpi_gid }} counter return {% endif %} meta mark {{ self_mark }} counter return {% if (zapret_enabled === '1'): %} meta mark {{ zapret_mark }} counter return meta mark and {{ zapret_desync_mark }} != 0 counter return {% endif /* zapret_enabled */ %} ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_mangle_mark {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_mangle_mark {% endif %} ip daddr @homeproxy_local_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_local_addr_v6 counter return {% endif %} ip daddr @homeproxy_wan_direct_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_wan_direct_addr_v6 counter return {% endif /* ipv6_support */ %} counter goto homeproxy_mangle_mark } chain mangle_prerouting { meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto udp jump homeproxy_mangle_lanac } chain mangle_output { meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto udp jump homeproxy_mangle_output } {% endif %} {# TUN #} {% if (match(proxy_mode, /tun/)): %} chain homeproxy_mangle_lanac { iifname {{ tun_name }} counter return udp dport 53 counter return {% if (control_info.listen_interfaces): %} meta iifname != {{ array_to_nftarr(control_info.listen_interfaces) }} counter return {% endif %} {% if (control_info.lan_proxy_mode === 'listed_only'): %} {% if (!isEmpty(control_info.lan_proxy_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_proxy_ipv4_ips) }} counter goto homeproxy_mangle_tun {% endif /* lan_proxy_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_proxy_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tun {% endfor /* lan_proxy_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_proxy_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_proxy_mac_addrs) }} counter goto homeproxy_mangle_tun {% endif /* lan_proxy_mac_addrs */ %} {% elif (control_info.lan_proxy_mode === 'except_listed'): %} {% if (!isEmpty(control_info.lan_direct_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_direct_ipv4_ips) }} counter return {% endif /* lan_direct_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_direct_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter return {% endfor /* lan_direct_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_direct_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_direct_mac_addrs) }} counter return {% endif /* lan_direct_mac_addrs */ %} {% endif /* lan_proxy_mode */ %} {% if (control_info.lan_proxy_mode !== 'listed_only'): %} counter goto homeproxy_mangle_tun {% endif %} } chain homeproxy_mangle_tun_mark { {% if (routing_port): %} {% if (proxy_mode === 'tun'): %} tcp dport != @homeproxy_routing_port counter return {% endif /* proxy_mode */ %} udp dport != @homeproxy_routing_port counter return {% endif /* routing_port */ %} counter meta mark set {{ tun_mark }} } chain homeproxy_mangle_tun { iifname {{ tun_name }} counter return ip daddr @homeproxy_wan_proxy_addr_v4 counter goto homeproxy_mangle_tun_mark {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_wan_proxy_addr_v6 counter goto homeproxy_mangle_tun_mark {% endif %} ip daddr @homeproxy_local_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_local_addr_v6 counter return {% endif %} {% if (routing_mode !== 'custom'): %} {% if (!isEmpty(control_info.lan_global_proxy_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_global_proxy_ipv4_ips) }} counter goto homeproxy_mangle_tun_mark {% endif /* lan_global_proxy_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_global_proxy_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter goto homeproxy_mangle_tun_mark {% endfor /* lan_global_proxy_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_global_proxy_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_global_proxy_mac_addrs) }} counter goto homeproxy_mangle_tun_mark {% endif /* lan_global_proxy_mac_addrs */ %} {% endif /* routing_mode */ %} {% if (control_info.wan_direct_ipv4_ips): %} ip daddr {{ array_to_nftarr(control_info.wan_direct_ipv4_ips) }} counter return {% endif /* wan_direct_ipv4_ips */ %} {% if (control_info.wan_direct_ipv6_ips): %} ip6 daddr {{ array_to_nftarr(control_info.wan_direct_ipv6_ips) }} counter return {% endif /* wan_direct_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_gaming_mode_ipv4_ips)): %} ip saddr {{ array_to_nftarr(control_info.lan_gaming_mode_ipv4_ips) }} counter meta mark set {{ tun_mark }} {% endif /* lan_gaming_mode_ipv4_ips */ %} {% for (let ipv6 in control_info.lan_gaming_mode_ipv6_ips): %} ip6 saddr {{ resolve_ipv6(ipv6) }} counter meta mark set {{ tun_mark }} {% endfor /* lan_gaming_mode_ipv6_ips */ %} {% if (!isEmpty(control_info.lan_gaming_mode_mac_addrs)): %} ether saddr {{ array_to_nftarr(control_info.lan_gaming_mode_mac_addrs) }} counter meta mark set {{ tun_mark }} {% endif /* lan_gaming_mode_mac_addrs */ %} counter goto homeproxy_mangle_tun_mark } chain mangle_prerouting { meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto { {{ (proxy_mode === 'tun') ? 'tcp, udp' : 'udp' }} } jump homeproxy_mangle_lanac } chain mangle_output { meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto { {{ (proxy_mode === 'tun') ? 'tcp, udp' : 'udp' }} } jump homeproxy_mangle_tun } {% endif %}