shadowsocks-libev: convert to using nft
[feed/packages.git] / net / shadowsocks-libev / files / ss-rules / chain.uc
diff --git a/net/shadowsocks-libev/files/ss-rules/chain.uc b/net/shadowsocks-libev/files/ss-rules/chain.uc
new file mode 100644 (file)
index 0000000..00362f6
--- /dev/null
@@ -0,0 +1,118 @@
+{%
+function get_local_verdict() {
+       let v = o_local_default;
+       if (v == "checkdst") {
+               return "goto ss_rules_dst_" + proto;
+       } else if (v == "forward") {
+               return "goto ss_rules_forward_" + proto;
+       } else {
+               return null;
+       }
+}
+
+function get_src_default_verdict() {
+       let v = o_src_default;
+       if (v == "checkdst") {
+               return "goto ss_rules_dst_" + proto;
+       } else if (v == "forward") {
+               return "goto ss_rules_forward_" + proto;
+       } else {
+               return "accept";
+       }
+}
+
+function get_dst_default_verdict() {
+       let v = o_dst_default;
+       if (v == "forward") {
+               return "goto ss_rules_forward_" + proto;
+       } else {
+               return "accept";
+       }
+}
+
+function get_ifnames() {
+       let res = [];
+       for (let ifname in split(o_ifnames, /[ \t\n]/)) {
+               ifname = trim(ifname);
+               if (ifname) push(res, ifname);
+       }
+       return res;
+}
+
+let type, hook, priority, redir_port;
+if (proto == "tcp") {
+       type = "nat";
+       hook = "prerouting";
+       priority = -1;
+       redir_port = o_redir_tcp_port;
+} else if (proto == "udp") {
+       type = "filter";
+       hook = "prerouting";
+       priority = "mangle";
+       redir_port = o_redir_udp_port;
+       if (system("
+               set -o errexit
+               while ip rule del fwmark 1 lookup 100 2>/dev/null; do true; done
+                     ip rule add fwmark 1 lookup 100
+               ip route flush table 100 2>/dev/null || true
+               ip route add local default dev lo table 100
+       ") != 0) {
+               return ;
+       }
+} else {
+       return;
+}
+
+%}
+{% if (redir_port): %}
+
+chain ss_rules_pre_{{ proto }} {
+       type {{ type }} hook {{ hook }} priority {{ priority }};
+       meta l4proto {{ proto }}{%- let ifnames=get_ifnames(); if (length(ifnames)): %} iifname { {{join(", ", ifnames)}} }{% endif %} goto ss_rules_pre_src_{{ proto }};
+}
+
+chain ss_rules_pre_src_{{ proto }} {
+       ip daddr @ss_rules_dst_bypass_ accept;
+       ip6 daddr @ss_rules6_dst_bypass_ accept;
+       goto ss_rules_src_{{ proto }};
+}
+
+chain ss_rules_src_{{ proto }} {
+       ip saddr @ss_rules_src_bypass accept;
+       ip saddr @ss_rules_src_forward goto ss_rules_forward_{{ proto }};
+       ip saddr @ss_rules_src_checkdst goto ss_rules_dst_{{ proto }};
+       ip6 saddr @ss_rules6_src_bypass accept;
+       ip6 saddr @ss_rules6_src_forward goto ss_rules_forward_{{ proto }};
+       ip6 saddr @ss_rules6_src_checkdst goto ss_rules_dst_{{ proto }};
+       {{ get_src_default_verdict() }};
+}
+
+chain ss_rules_dst_{{ proto }} {
+       ip daddr @ss_rules_dst_bypass accept;
+       ip daddr @ss_rules_dst_forward goto ss_rules_forward_{{ proto }};
+       ip6 daddr @ss_rules6_dst_bypass accept;
+       ip6 daddr @ss_rules6_dst_forward goto ss_rules_forward_{{ proto }};
+       {{ get_dst_default_verdict() }};
+}
+
+{%   if (proto == "tcp"): %}
+chain ss_rules_forward_{{ proto }} {
+       meta l4proto tcp redirect to :{{ redir_port }};
+}
+{%   let local_verdict = get_local_verdict(); if (local_verdict): %}
+chain ss_rules_local_out {
+       type {{ type }} hook output priority -1;
+       meta l4proto != tcp accept;
+       ip daddr @ss_rules_dst_bypass_ accept;
+       ip daddr @ss_rules_dst_bypass accept;
+       ip6 daddr @ss_rules6_dst_bypass_ accept;
+       ip6 daddr @ss_rules6_dst_bypass accept;
+       {{ local_verdict }};
+}
+{%     endif %}
+{%   elif (proto == "udp"): %}
+chain ss_rules_forward_{{ proto }} {
+       meta l4proto udp meta mark set 1 tproxy to :{{ redir_port }};
+}
+{%   endif %}
+{% endif %}