OSDN Git Service

firewall4: add fullcone support
[immortalwrt/immortalwrt.git] / package / network / config / firewall4 / patches / 001-firewall4-add-support-for-fullcone-nat.patch
1 From 980594ee7bcb0bcded95731bb12cf118d7f48951 Mon Sep 17 00:00:00 2001
2 From: Syrone Wong <wong.syrone@gmail.com>
3 Date: Sat, 9 Apr 2022 13:24:19 +0800
4 Subject: [PATCH] firewall4: add fullcone support
5
6 fullcone is drop-in replacement of masq for non-udp traffic
7
8 add runtime fullcone rule check, disable it globally if fullcone expr is
9 invalid
10 ---
11  root/etc/config/firewall                      |  2 +
12  root/usr/share/firewall4/templates/ruleset.uc | 13 +++++-
13  .../firewall4/templates/zone-fullcone.uc      |  4 ++
14  root/usr/share/ucode/fw4.uc                   | 44 ++++++++++++++++++-
15  4 files changed, 60 insertions(+), 3 deletions(-)
16  create mode 100644 root/usr/share/firewall4/templates/zone-fullcone.uc
17
18 diff --git a/root/etc/config/firewall b/root/etc/config/firewall
19 index f4a3322..2f17ad2 100644
20 --- a/root/etc/config/firewall
21 +++ b/root/etc/config/firewall
22 @@ -5,6 +5,7 @@ config defaults
23         option forward          REJECT
24  # Uncomment this line to disable ipv6 rules
25  #      option disable_ipv6     1
26 +       option fullcone '1'
27  
28  config zone
29         option name             lan
30 @@ -20,6 +21,7 @@ config zone
31         option input            REJECT
32         option output           ACCEPT
33         option forward          REJECT
34 +       option fullcone '1'
35         option masq             1
36         option mtu_fix          1
37  
38 diff --git a/root/usr/share/firewall4/templates/ruleset.uc b/root/usr/share/firewall4/templates/ruleset.uc
39 index b402315..aae698f 100644
40 --- a/root/usr/share/firewall4/templates/ruleset.uc
41 +++ b/root/usr/share/firewall4/templates/ruleset.uc
42 @@ -1,3 +1,4 @@
43 +{# /usr/share/firewall4/templates/ruleset.uc #}
44  {% let flowtable_devices = fw4.resolve_offload_devices(); -%}
45  
46  table inet fw4
47 @@ -237,6 +238,10 @@ table inet fw4 {
48  {%   for (let redirect in fw4.redirects("dstnat_"+zone.name)): %}
49                 {%+ include("redirect.uc", { fw4, redirect }) %}
50  {%   endfor %}
51 +{%   if (zone.fullcone): %}
52 +               {%+ include("zone-fullcone.uc", { fw4, zone, direction: "dstnat" }) %}
53 +{%   endif %}
54 +
55         }
56  
57  {%  endif %}
58 @@ -245,20 +250,24 @@ table inet fw4 {
59  {%   for (let redirect in fw4.redirects("srcnat_"+zone.name)): %}
60                 {%+ include("redirect.uc", { fw4, redirect }) %}
61  {%   endfor %}
62 -{%   if (zone.masq): %}
63 +{%   if (zone.masq && !zone.fullcone): %}
64  {%    for (let saddrs in zone.masq4_src_subnets): %}
65  {%     for (let daddrs in zone.masq4_dest_subnets): %}
66                 {%+ include("zone-masq.uc", { fw4, zone, family: 4, saddrs, daddrs }) %}
67  {%     endfor %}
68  {%    endfor %}
69  {%   endif %}
70 -{%   if (zone.masq6): %}
71 +{%   if (zone.masq6 && !zone.fullcone): %}
72  {%    for (let saddrs in zone.masq6_src_subnets): %}
73  {%     for (let daddrs in zone.masq6_dest_subnets): %}
74                 {%+ include("zone-masq.uc", { fw4, zone, family: 6, saddrs, daddrs }) %}
75  {%     endfor %}
76  {%    endfor %}
77  {%   endif %}
78 +{%   if (zone.fullcone): %}
79 +               {%+ include("zone-fullcone.uc", { fw4, zone, direction: "srcnat" }) %}
80 +{%   endif %}
81 +
82         }
83  
84  {%  endif %}
85 diff --git a/root/usr/share/firewall4/templates/zone-fullcone.uc b/root/usr/share/firewall4/templates/zone-fullcone.uc
86 new file mode 100644
87 index 0000000..f0647da
88 --- /dev/null
89 +++ b/root/usr/share/firewall4/templates/zone-fullcone.uc
90 @@ -0,0 +1,4 @@
91 +{# /usr/share/firewall4/templates/zone-fullcone.uc #}
92 +               fullcone comment "!fw4: Handle {{
93 +               zone.name
94 +}} IPv4/IPv6 fullcone NAT traffic"
95 diff --git a/root/usr/share/ucode/fw4.uc b/root/usr/share/ucode/fw4.uc
96 index b81f9ad..ec5958e 100644
97 --- a/root/usr/share/ucode/fw4.uc
98 +++ b/root/usr/share/ucode/fw4.uc
99 @@ -1,3 +1,5 @@
100 +// /usr/share/ucode/fw4.uc
101 +
102  let fs = require("fs");
103  let uci = require("uci");
104  let ubus = require("ubus");
105 @@ -419,6 +421,25 @@ function nft_try_hw_offload(devices) {
106         return (rc == 0);
107  }
108  
109 +function nft_try_fullcone() {
110 +       let nft_test =
111 +               'add table inet fw4-fullcone-test; ' +
112 +               'add chain inet fw4-fullcone-test dstnat { ' +
113 +                       'type nat hook prerouting priority -100; policy accept; ' +
114 +                       'fullcone; ' +
115 +               '}; ' +
116 +               'add chain inet fw4-fullcone-test srcnat { ' +
117 +                       'type nat hook postrouting priority -100; policy accept; ' +
118 +                       'fullcone; ' +
119 +               '}; ';
120 +       let cmd = sprintf("/usr/sbin/nft -c '%s' 2>/dev/null", replace(nft_test, "'", "'\\''"));
121 +       let ok = system(cmd) == 0;
122 +       if (!ok) {
123 +               warn("nft_try_fullcone: cmd "+ cmd + "\n");
124 +       }
125 +       return ok;
126 +}
127 +
128  
129  return {
130         read_kernel_version: function() {
131 @@ -1382,6 +1403,7 @@ return {
132                         "dnat",
133                         "snat",
134                         "masquerade",
135 +                       "fullcone",
136                         "accept",
137                         "reject",
138                         "drop"
139 @@ -1787,6 +1809,7 @@ return {
140                 }
141  
142                 let defs = this.parse_options(data, {
143 +                       fullcone: [ "bool", "0" ],
144                         input: [ "policy", "drop" ],
145                         output: [ "policy", "drop" ],
146                         forward: [ "policy", "drop" ],
147 @@ -1819,6 +1842,11 @@ return {
148  
149                 delete defs.syn_flood;
150  
151 +               if (!nft_try_fullcone()) {
152 +                       delete defs.fullcone;
153 +                       warn("nft_try_fullcone failed, disable fullcone globally\n");
154 +               }
155 +
156                 this.state.defaults = defs;
157         },
158  
159 @@ -1843,6 +1871,7 @@ return {
160                         masq_dest: [ "network", null, PARSE_LIST ],
161  
162                         masq6: [ "bool" ],
163 +                       fullcone: [ "bool", "0" ],
164  
165                         extra: [ "string", null, UNSUPPORTED ],
166                         extra_src: [ "string", null, UNSUPPORTED ],
167 @@ -1873,6 +1902,14 @@ return {
168                         return;
169                 }
170  
171 +               if (this.state.defaults && !this.state.defaults.fullcone) {
172 +                       this.warn_section(data, "fullcone in defaults not enabled, ignore zone fullcone setting");
173 +                       zone.fullcone = false;
174 +               }
175 +               if (zone.fullcone) {
176 +                       this.warn_section(data, "fullcone enabled for zone '" + zone.name + "'");
177 +               }
178 +
179                 if (zone.mtu_fix && this.kernel < 0x040a0000) {
180                         this.warn_section(data, "option 'mtu_fix' requires kernel 4.10 or later");
181                         return;
182 @@ -2041,10 +2078,15 @@ return {
183                 zone.related_subnets = related_subnets;
184                 zone.related_physdevs = related_physdevs;
185  
186 +               if (zone.fullcone) {
187 +                       zone.dflags.snat = true;
188 +                       zone.dflags.dnat = true;
189 +               }
190 +
191                 if (zone.masq || zone.masq6)
192                         zone.dflags.snat = true;
193  
194 -               if ((zone.auto_helper && !(zone.masq || zone.masq6)) || length(zone.helper)) {
195 +               if ((zone.auto_helper && !(zone.masq || zone.masq6 || zone.fullcone)) || length(zone.helper)) {
196                         zone.dflags.helper = true;
197  
198                         for (let helper in (length(zone.helper) ? zone.helper : this.state.helpers)) {