#!/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') || 'bypass_mainland_china'; let outbound_node, outbound_udp_node, china_dns_server, bypass_cn_traffic; if (routing_mode !== 'custom') { outbound_node = uci.get(cfgname, 'config', 'main_node') || 'nil'; outbound_udp_node = uci.get(cfgname, 'config', 'main_udp_node') || 'nil'; china_dns_server = uci.get(cfgname, 'config', 'china_dns_server'); } else { outbound_node = uci.get(cfgname, 'routing', 'default_outbound') || 'nil'; bypass_cn_traffic = uci.get(cfgname, 'routing', 'bypass_cn_traffic') || '0'; } 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; 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') { 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_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 %} {% if (routing_mode === 'gfwlist'): %} set homeproxy_gfw_list_v4 { type ipv4_addr flags interval auto-merge } {% if (ipv6_support === '1'): %} set homeproxy_gfw_list_v6 { type ipv6_addr flags interval auto-merge } {% endif /* ipv6_support */ %} {% elif (match(routing_mode, /mainland_china/) || bypass_cn_traffic === '1'): %} set homeproxy_mainland_addr_v4 { type ipv4_addr flags interval auto-merge elements = { {% for (let cnip4 in split(trim(readfile(resources_dir + '/china_ip4.txt')), /[\r\n]/)): %} {{ cnip4 }}, {% endfor %} } } {% if ((ipv6_support === '1') || china_dns_server): %} set homeproxy_mainland_addr_v6 { type ipv6_addr flags interval auto-merge elements = { {% for (let cnip6 in split(trim(readfile(resources_dir + '/china_ip6.txt')), /[\r\n]/)): %} {{ cnip6 }}, {% endfor %} } } {% endif /* ipv6_support */ %} {% endif /* routing_mode */ %} {# 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_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 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 (routing_mode === 'gfwlist'): %} ip daddr != @homeproxy_gfw_list_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_gfw_list_v6 counter return {% endif /* ipv6_support */ %} {% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %} ip daddr @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% elif (routing_mode === 'proxy_mainland_china'): %} ip daddr != @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% endif /* routing_mode */ %} {% 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 meta nfproto { {{ (ipv6_support === '1') ? 'ipv4, ipv6' : 'ipv4' }} } meta l4proto tcp jump homeproxy_redirect } {% endif %} {# UDP tproxy #} {% if (match(proxy_mode, /tproxy/) && (outbound_udp_node !== 'nil' || routing_mode === 'custom')): %} 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 (routing_mode === 'gfwlist'): %} ip daddr != @homeproxy_gfw_list_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_gfw_list_v6 counter return {% endif /* ipv6_support */ %} udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC" {% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %} ip daddr @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% if (routing_mode !== 'custom'): %} udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC" {% endif /* routing_mode */ %} {% elif (routing_mode === 'proxy_mainland_china'): %} ip daddr != @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% endif /* routing_mode */ %} {% 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 { meta mark {{ self_mark }} counter return 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 */ %} {% if (routing_mode === 'gfwlist'): %} ip daddr != @homeproxy_gfw_list_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_gfw_list_v6 counter return {% endif /* ipv6_support */ %} {% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %} ip daddr @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% elif (routing_mode === 'proxy_mainland_china'): %} ip daddr != @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% endif /* routing_mode */ %} 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 (routing_mode === 'gfwlist'): %} ip daddr != @homeproxy_gfw_list_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_gfw_list_v6 counter return {% endif /* ipv6_support */ %} udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC" {% elif (routing_mode === 'bypass_mainland_china' || bypass_cn_traffic === '1'): %} ip daddr @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% if (routing_mode !== 'custom'): %} udp dport { 80, 443 } counter reject comment "!{{ cfgname }}: Fuck you QUIC" {% endif /* routing_mode */ %} {% elif (routing_mode === 'proxy_mainland_china'): %} ip daddr != @homeproxy_mainland_addr_v4 counter return {% if (ipv6_support === '1'): %} ip6 daddr != @homeproxy_mainland_addr_v6 counter return {% endif /* ipv6_support */ %} {% endif /* routing_mode */ %} {% 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 %}