zones: disable masq when resolving of all masq_src or masq_dest items failed
[project/firewall3.git] / zones.c
1 /*
2  * firewall3 - 3rd OpenWrt UCI firewall implementation
3  *
4  *   Copyright (C) 2013 Jo-Philipp Wich <jo@mein.io>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include "zones.h"
20 #include "ubus.h"
21
22
23 #define C(f, tbl, tgt, fmt) \
24         { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_FLAG_##tgt, fmt }
25
26 static const struct fw3_chain_spec zone_chains[] = {
27         C(ANY, FILTER, UNSPEC,        "zone_%s_input"),
28         C(ANY, FILTER, UNSPEC,        "zone_%s_output"),
29         C(ANY, FILTER, UNSPEC,        "zone_%s_forward"),
30
31         C(ANY, FILTER, SRC_ACCEPT,    "zone_%s_src_ACCEPT"),
32         C(ANY, FILTER, SRC_REJECT,    "zone_%s_src_REJECT"),
33         C(ANY, FILTER, SRC_DROP,      "zone_%s_src_DROP"),
34
35         C(ANY, FILTER, ACCEPT,        "zone_%s_dest_ACCEPT"),
36         C(ANY, FILTER, REJECT,        "zone_%s_dest_REJECT"),
37         C(ANY, FILTER, DROP,          "zone_%s_dest_DROP"),
38
39         C(V4,  NAT,    SNAT,          "zone_%s_postrouting"),
40         C(V4,  NAT,    DNAT,          "zone_%s_prerouting"),
41
42         C(ANY, RAW,    NOTRACK,       "zone_%s_notrack"),
43
44         C(ANY, FILTER, CUSTOM_CHAINS, "input_%s_rule"),
45         C(ANY, FILTER, CUSTOM_CHAINS, "output_%s_rule"),
46         C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_%s_rule"),
47
48         C(V4,  NAT,    CUSTOM_CHAINS, "prerouting_%s_rule"),
49         C(V4,  NAT,    CUSTOM_CHAINS, "postrouting_%s_rule"),
50
51         { }
52 };
53
54 const struct fw3_option fw3_zone_opts[] = {
55         FW3_OPT("enabled",             bool,     zone,     enabled),
56
57         FW3_OPT("name",                string,   zone,     name),
58         FW3_OPT("family",              family,   zone,     family),
59
60         FW3_LIST("network",            device,   zone,     networks),
61         FW3_LIST("device",             device,   zone,     devices),
62         FW3_LIST("subnet",             network,  zone,     subnets),
63
64         FW3_OPT("input",               target,   zone,     policy_input),
65         FW3_OPT("forward",             target,   zone,     policy_forward),
66         FW3_OPT("output",              target,   zone,     policy_output),
67
68         FW3_OPT("masq",                bool,     zone,     masq),
69         FW3_OPT("masq_allow_invalid",  bool,     zone,     masq_allow_invalid),
70         FW3_LIST("masq_src",           network,  zone,     masq_src),
71         FW3_LIST("masq_dest",          network,  zone,     masq_dest),
72
73         FW3_OPT("extra",               string,   zone,     extra_src),
74         FW3_OPT("extra_src",           string,   zone,     extra_src),
75         FW3_OPT("extra_dest",          string,   zone,     extra_dest),
76
77         FW3_OPT("mtu_fix",             bool,     zone,     mtu_fix),
78         FW3_OPT("custom_chains",       bool,     zone,     custom_chains),
79
80         FW3_OPT("log",                 bool,     zone,     log),
81         FW3_OPT("log_limit",           limit,    zone,     log_limit),
82
83         FW3_OPT("__flags_v4",          int,      zone,     flags[0]),
84         FW3_OPT("__flags_v6",          int,      zone,     flags[1]),
85
86         FW3_LIST("__addrs",            address,  zone,     old_addrs),
87
88         { }
89 };
90
91
92 static void
93 check_policy(struct uci_element *e, enum fw3_flag *pol, enum fw3_flag def,
94              const char *name)
95 {
96         if (*pol == FW3_FLAG_UNSPEC)
97         {
98                 warn_elem(e, "has no %s policy specified, using default", name);
99                 *pol = def;
100         }
101         else if (*pol > FW3_FLAG_DROP)
102         {
103                 warn_elem(e, "has invalid %s policy, using default", name);
104                 *pol = def;
105         }
106 }
107
108 static bool
109 check_masq_addrs(struct list_head *head)
110 {
111         struct fw3_address *addr;
112         int n_addr = 0, n_failed = 0;
113
114         list_for_each_entry(addr, head, list)
115         {
116                 if (addr->invert)
117                         continue;
118
119                 n_addr++;
120
121                 if (!addr->set && addr->resolved)
122                         n_failed++;
123         }
124
125         return (n_addr == 0 || n_failed < n_addr);
126 }
127
128 static void
129 resolve_networks(struct uci_element *e, struct fw3_zone *zone)
130 {
131         struct fw3_device *net, *tmp;
132
133         list_for_each_entry(net, &zone->networks, list)
134         {
135                 tmp = fw3_ubus_device(net->name);
136
137                 if (!tmp)
138                 {
139                         warn_elem(e, "cannot resolve device of network '%s'", net->name);
140                         continue;
141                 }
142
143                 snprintf(tmp->network, sizeof(tmp->network), "%s", net->name);
144                 list_add_tail(&tmp->list, &zone->devices);
145         }
146 }
147
148 struct fw3_zone *
149 fw3_alloc_zone(void)
150 {
151         struct fw3_zone *zone;
152
153         zone = calloc(1, sizeof(*zone));
154         if (!zone)
155                 return NULL;
156
157         INIT_LIST_HEAD(&zone->networks);
158         INIT_LIST_HEAD(&zone->devices);
159         INIT_LIST_HEAD(&zone->subnets);
160         INIT_LIST_HEAD(&zone->masq_src);
161         INIT_LIST_HEAD(&zone->masq_dest);
162
163         INIT_LIST_HEAD(&zone->old_addrs);
164
165         zone->enabled = true;
166         zone->custom_chains = true;
167         zone->log_limit.rate = 10;
168
169         return zone;
170 }
171
172 void
173 fw3_load_zones(struct fw3_state *state, struct uci_package *p)
174 {
175         struct uci_section *s;
176         struct uci_element *e;
177         struct fw3_zone *zone;
178         struct fw3_defaults *defs = &state->defaults;
179
180         INIT_LIST_HEAD(&state->zones);
181
182         uci_foreach_element(&p->sections, e)
183         {
184                 s = uci_to_section(e);
185
186                 if (strcmp(s->type, "zone"))
187                         continue;
188
189                 zone = fw3_alloc_zone();
190
191                 if (!zone)
192                         continue;
193
194                 if (!fw3_parse_options(zone, fw3_zone_opts, s))
195                         warn_elem(e, "has invalid options");
196
197                 if (!zone->enabled)
198                 {
199                         fw3_free_zone(zone);
200                         continue;
201                 }
202
203                 if (!zone->extra_dest)
204                         zone->extra_dest = zone->extra_src;
205
206                 if (!defs->custom_chains && zone->custom_chains)
207                         zone->custom_chains = false;
208
209                 if (!zone->name || !*zone->name)
210                 {
211                         warn_elem(e, "has no name - ignoring");
212                         fw3_free_zone(zone);
213                         continue;
214                 }
215
216                 if (strlen(zone->name) > FW3_ZONE_MAXNAMELEN)
217                 {
218                         warn_elem(e, "must not have a name longer than %u characters",
219                                      FW3_ZONE_MAXNAMELEN);
220                         fw3_free_zone(zone);
221                         continue;
222                 }
223
224                 fw3_ubus_zone_devices(zone);
225
226                 if (list_empty(&zone->networks) && list_empty(&zone->devices) &&
227                     list_empty(&zone->subnets) && !zone->extra_src)
228                 {
229                         warn_elem(e, "has no device, network, subnet or extra options");
230                 }
231
232                 if (!check_masq_addrs(&zone->masq_src))
233                 {
234                         warn_elem(e, "has unresolved masq_src, disabling masq");
235                         zone->masq = false;
236                 }
237
238                 if (!check_masq_addrs(&zone->masq_dest))
239                 {
240                         warn_elem(e, "has unresolved masq_dest, disabling masq");
241                         zone->masq = false;
242                 }
243
244                 check_policy(e, &zone->policy_input, defs->policy_input, "input");
245                 check_policy(e, &zone->policy_output, defs->policy_output, "output");
246                 check_policy(e, &zone->policy_forward, defs->policy_forward, "forward");
247
248                 resolve_networks(e, zone);
249
250                 if (zone->masq)
251                 {
252                         fw3_setbit(zone->flags[0], FW3_FLAG_SNAT);
253                 }
254
255                 if (zone->custom_chains)
256                 {
257                         fw3_setbit(zone->flags[0], FW3_FLAG_SNAT);
258                         fw3_setbit(zone->flags[0], FW3_FLAG_DNAT);
259                 }
260
261                 fw3_setbit(zone->flags[0], fw3_to_src_target(zone->policy_input));
262                 fw3_setbit(zone->flags[0], zone->policy_forward);
263                 fw3_setbit(zone->flags[0], zone->policy_output);
264
265                 fw3_setbit(zone->flags[1], fw3_to_src_target(zone->policy_input));
266                 fw3_setbit(zone->flags[1], zone->policy_forward);
267                 fw3_setbit(zone->flags[1], zone->policy_output);
268
269                 list_add_tail(&zone->list, &state->zones);
270         }
271 }
272
273
274 static void
275 print_zone_chain(struct fw3_ipt_handle *handle, struct fw3_state *state,
276                  bool reload, struct fw3_zone *zone)
277 {
278         int i;
279         struct fw3_ipt_rule *r;
280         const struct fw3_chain_spec *c;
281
282         const char *flt_chains[] = {
283                 "input",   "input",
284                 "output",  "output",
285                 "forward", "forwarding",
286         };
287
288         const char *nat_chains[] = {
289                 "prerouting",  "prerouting",
290                 "postrouting", "postrouting",
291         };
292
293         if (!fw3_is_family(zone, handle->family))
294                 return;
295
296         info("   * Zone '%s'", zone->name);
297
298         set(zone->flags, handle->family, handle->table);
299
300         if (zone->custom_chains)
301                 set(zone->flags, handle->family, FW3_FLAG_CUSTOM_CHAINS);
302
303         for (c = zone_chains; c->format; c++)
304         {
305                 /* don't touch user chains on selective stop */
306                 if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS)
307                         continue;
308
309                 if (!fw3_is_family(c, handle->family))
310                         continue;
311
312                 if (c->table != handle->table)
313                         continue;
314
315                 if (c->flag &&
316                     !fw3_hasbit(zone->flags[handle->family == FW3_FAMILY_V6], c->flag))
317                         continue;
318
319                 fw3_ipt_create_chain(handle, c->format, zone->name);
320         }
321
322         if (zone->custom_chains)
323         {
324                 if (handle->table == FW3_TABLE_FILTER)
325                 {
326                         for (i = 0; i < sizeof(flt_chains)/sizeof(flt_chains[0]); i += 2)
327                         {
328                                 r = fw3_ipt_rule_new(handle);
329                                 fw3_ipt_rule_comment(r, "user chain for %s", flt_chains[i+1]);
330                                 fw3_ipt_rule_target(r, "%s_%s_rule", flt_chains[i+1], zone->name);
331                                 fw3_ipt_rule_append(r, "zone_%s_%s", zone->name, flt_chains[i]);
332                         }
333                 }
334                 else if (handle->table == FW3_TABLE_NAT)
335                 {
336                         for (i = 0; i < sizeof(nat_chains)/sizeof(nat_chains[0]); i += 2)
337                         {
338                                 r = fw3_ipt_rule_new(handle);
339                                 fw3_ipt_rule_comment(r, "user chain for %s", nat_chains[i+1]);
340                                 fw3_ipt_rule_target(r, "%s_%s_rule", nat_chains[i+1], zone->name);
341                                 fw3_ipt_rule_append(r, "zone_%s_%s", zone->name, nat_chains[i]);
342                         }
343                 }
344         }
345
346         set(zone->flags, handle->family, handle->table);
347 }
348
349 static void
350 print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
351                                          bool reload, struct fw3_zone *zone,
352                      struct fw3_device *dev, struct fw3_address *sub)
353 {
354         struct fw3_protocol tcp = { .protocol = 6 };
355         struct fw3_ipt_rule *r;
356         enum fw3_flag t;
357
358         char buf[32];
359
360         int i;
361
362         const char *chains[] = {
363                 "input", "INPUT",
364                 "output", "OUTPUT",
365                 "forward", "FORWARD",
366         };
367
368 #define jump_target(t) \
369         ((t == FW3_FLAG_REJECT) ? "reject" : fw3_flag_names[t])
370
371         if (handle->table == FW3_TABLE_FILTER)
372         {
373                 for (t = FW3_FLAG_ACCEPT; t <= FW3_FLAG_DROP; t++)
374                 {
375                         if (has(zone->flags, handle->family, fw3_to_src_target(t)))
376                         {
377                                 r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
378                                 fw3_ipt_rule_target(r, jump_target(t));
379                                 fw3_ipt_rule_extra(r, zone->extra_src);
380
381                                 if (t == FW3_FLAG_ACCEPT && !state->defaults.drop_invalid)
382                                         fw3_ipt_rule_extra(r,
383                                                            "-m conntrack --ctstate NEW,UNTRACKED");
384
385                                 fw3_ipt_rule_replace(r, "zone_%s_src_%s", zone->name,
386                                                      fw3_flag_names[t]);
387                         }
388
389                         if (has(zone->flags, handle->family, t))
390                         {
391                                 if (t == FW3_FLAG_ACCEPT &&
392                                     zone->masq && !zone->masq_allow_invalid)
393                                 {
394                                         r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
395                                         fw3_ipt_rule_extra(r, "-m conntrack --ctstate INVALID");
396                                         fw3_ipt_rule_comment(r, "Prevent NAT leakage");
397                                         fw3_ipt_rule_target(r, fw3_flag_names[FW3_FLAG_DROP]);
398                                         fw3_ipt_rule_replace(r, "zone_%s_dest_%s", zone->name,
399                                                              fw3_flag_names[t]);
400                                 }
401
402                                 r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
403                                 fw3_ipt_rule_target(r, jump_target(t));
404                                 fw3_ipt_rule_extra(r, zone->extra_dest);
405                                 fw3_ipt_rule_replace(r, "zone_%s_dest_%s", zone->name,
406                                                      fw3_flag_names[t]);
407                         }
408                 }
409
410                 for (i = 0; i < sizeof(chains)/sizeof(chains[0]); i += 2)
411                 {
412                         if (*chains[i] == 'o')
413                                 r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
414                         else
415                                 r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
416
417                         fw3_ipt_rule_target(r, "zone_%s_%s", zone->name, chains[i]);
418
419                         if (*chains[i] == 'o')
420                                 fw3_ipt_rule_extra(r, zone->extra_dest);
421                         else
422                                 fw3_ipt_rule_extra(r, zone->extra_src);
423
424                         fw3_ipt_rule_replace(r, chains[i + 1]);
425                 }
426         }
427         else if (handle->table == FW3_TABLE_NAT)
428         {
429                 if (has(zone->flags, handle->family, FW3_FLAG_DNAT))
430                 {
431                         r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
432                         fw3_ipt_rule_target(r, "zone_%s_prerouting", zone->name);
433                         fw3_ipt_rule_extra(r, zone->extra_src);
434                         fw3_ipt_rule_replace(r, "PREROUTING");
435                 }
436
437                 if (has(zone->flags, handle->family, FW3_FLAG_SNAT))
438                 {
439                         r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
440                         fw3_ipt_rule_target(r, "zone_%s_postrouting", zone->name);
441                         fw3_ipt_rule_extra(r, zone->extra_dest);
442                         fw3_ipt_rule_replace(r, "POSTROUTING");
443                 }
444         }
445         else if (handle->table == FW3_TABLE_MANGLE)
446         {
447                 if (zone->mtu_fix)
448                 {
449                         if (zone->log)
450                         {
451                                 snprintf(buf, sizeof(buf) - 1, "MSSFIX(%s): ", zone->name);
452
453                                 r = fw3_ipt_rule_create(handle, &tcp, NULL, dev, NULL, sub);
454                                 fw3_ipt_rule_addarg(r, false, "--tcp-flags", "SYN,RST");
455                                 fw3_ipt_rule_addarg(r, false, "SYN", NULL);
456                                 fw3_ipt_rule_limit(r, &zone->log_limit);
457                                 fw3_ipt_rule_comment(r, "%s (mtu_fix logging)", zone->name);
458                                 fw3_ipt_rule_target(r, "LOG");
459                                 fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
460                                 fw3_ipt_rule_replace(r, "FORWARD");
461                         }
462
463                         r = fw3_ipt_rule_create(handle, &tcp, NULL, dev, NULL, sub);
464                         fw3_ipt_rule_addarg(r, false, "--tcp-flags", "SYN,RST");
465                         fw3_ipt_rule_addarg(r, false, "SYN", NULL);
466                         fw3_ipt_rule_comment(r, "%s (mtu_fix)", zone->name);
467                         fw3_ipt_rule_target(r, "TCPMSS");
468                         fw3_ipt_rule_addarg(r, false, "--clamp-mss-to-pmtu", NULL);
469                         fw3_ipt_rule_replace(r, "FORWARD");
470                 }
471         }
472         else if (handle->table == FW3_TABLE_RAW)
473         {
474                 if (has(zone->flags, handle->family, FW3_FLAG_NOTRACK))
475                 {
476                         r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
477                         fw3_ipt_rule_target(r, "zone_%s_notrack", zone->name);
478                         fw3_ipt_rule_extra(r, zone->extra_src);
479                         fw3_ipt_rule_replace(r, "PREROUTING");
480                 }
481         }
482 }
483
484 static void
485 print_interface_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
486                       bool reload, struct fw3_zone *zone)
487 {
488         struct fw3_device *dev;
489         struct fw3_address *sub;
490
491         fw3_foreach(dev, &zone->devices)
492         fw3_foreach(sub, &zone->subnets)
493         {
494                 if (!fw3_is_family(sub, handle->family))
495                         continue;
496
497                 if (!dev && !sub)
498                         continue;
499
500                 print_interface_rule(handle, state, reload, zone, dev, sub);
501         }
502 }
503
504 static struct fw3_address *
505 next_addr(struct fw3_address *addr, struct list_head *list,
506                 enum fw3_family family, bool invert)
507 {
508         struct list_head *p;
509         struct fw3_address *rv;
510
511         for (p = addr ? addr->list.next : list->next; p != list; p = p->next)
512         {
513                 rv = list_entry(p, struct fw3_address, list);
514
515                 if (fw3_is_family(rv, family) && rv->set && rv->invert == invert)
516                         return rv;
517         }
518
519         return NULL;
520 }
521
522 static void
523 print_zone_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
524                 bool reload, struct fw3_zone *zone)
525 {
526         bool first_src, first_dest;
527         struct fw3_address *msrc;
528         struct fw3_address *mdest;
529         struct fw3_ipt_rule *r;
530
531         enum fw3_flag t;
532         char buf[32];
533
534         if (!fw3_is_family(zone, handle->family))
535                 return;
536
537         switch (handle->table)
538         {
539         case FW3_TABLE_FILTER:
540                 if (has(zone->flags, handle->family, FW3_FLAG_DNAT))
541                 {
542                         r = fw3_ipt_rule_new(handle);
543                         fw3_ipt_rule_extra(r, "-m conntrack --ctstate DNAT");
544                         fw3_ipt_rule_comment(r, "Accept port redirections");
545                         fw3_ipt_rule_target(r, fw3_flag_names[FW3_FLAG_ACCEPT]);
546                         fw3_ipt_rule_append(r, "zone_%s_input", zone->name);
547
548                         r = fw3_ipt_rule_new(handle);
549                         fw3_ipt_rule_extra(r, "-m conntrack --ctstate DNAT");
550                         fw3_ipt_rule_comment(r, "Accept port forwards");
551                         fw3_ipt_rule_target(r, fw3_flag_names[FW3_FLAG_ACCEPT]);
552                         fw3_ipt_rule_append(r, "zone_%s_forward", zone->name);
553                 }
554
555                 r = fw3_ipt_rule_new(handle);
556                 fw3_ipt_rule_target(r, "zone_%s_src_%s", zone->name,
557                                      fw3_flag_names[zone->policy_input]);
558                 fw3_ipt_rule_append(r, "zone_%s_input", zone->name);
559
560                 r = fw3_ipt_rule_new(handle);
561                 fw3_ipt_rule_target(r, "zone_%s_dest_%s", zone->name,
562                                      fw3_flag_names[zone->policy_forward]);
563                 fw3_ipt_rule_append(r, "zone_%s_forward", zone->name);
564
565                 r = fw3_ipt_rule_new(handle);
566                 fw3_ipt_rule_target(r, "zone_%s_dest_%s", zone->name,
567                                      fw3_flag_names[zone->policy_output]);
568                 fw3_ipt_rule_append(r, "zone_%s_output", zone->name);
569
570                 if (zone->log)
571                 {
572                         for (t = FW3_FLAG_REJECT; t <= FW3_FLAG_DROP; t++)
573                         {
574                                 if (has(zone->flags, handle->family, fw3_to_src_target(t)))
575                                 {
576                                         r = fw3_ipt_rule_new(handle);
577
578                                         snprintf(buf, sizeof(buf) - 1, "%s(src %s)",
579                                                  fw3_flag_names[t], zone->name);
580
581                                         fw3_ipt_rule_limit(r, &zone->log_limit);
582                                         fw3_ipt_rule_target(r, "LOG");
583                                         fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
584                                         fw3_ipt_rule_append(r, "zone_%s_src_%s",
585                                                             zone->name, fw3_flag_names[t]);
586                                 }
587
588                                 if (has(zone->flags, handle->family, t))
589                                 {
590                                         r = fw3_ipt_rule_new(handle);
591
592                                         snprintf(buf, sizeof(buf) - 1, "%s(dest %s)",
593                                                  fw3_flag_names[t], zone->name);
594
595                                         fw3_ipt_rule_limit(r, &zone->log_limit);
596                                         fw3_ipt_rule_target(r, "LOG");
597                                         fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
598                                         fw3_ipt_rule_append(r, "zone_%s_dest_%s",
599                                                             zone->name, fw3_flag_names[t]);
600                                 }
601                         }
602                 }
603                 break;
604
605         case FW3_TABLE_NAT:
606                 if (zone->masq && handle->family == FW3_FAMILY_V4)
607                 {
608                         /* for any negated masq_src ip, emit -s addr -j RETURN rules */
609                         for (msrc = NULL;
610                              (msrc = next_addr(msrc, &zone->masq_src,
611                                                handle->family, true)) != NULL; )
612                         {
613                                 msrc->invert = false;
614                                 r = fw3_ipt_rule_new(handle);
615                                 fw3_ipt_rule_src_dest(r, msrc, NULL);
616                                 fw3_ipt_rule_target(r, "RETURN");
617                                 fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name);
618                                 msrc->invert = true;
619                         }
620
621                         /* for any negated masq_dest ip, emit -d addr -j RETURN rules */
622                         for (mdest = NULL;
623                              (mdest = next_addr(mdest, &zone->masq_dest,
624                                                 handle->family, true)) != NULL; )
625                         {
626                                 mdest->invert = false;
627                                 r = fw3_ipt_rule_new(handle);
628                                 fw3_ipt_rule_src_dest(r, NULL, mdest);
629                                 fw3_ipt_rule_target(r, "RETURN");
630                                 fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name);
631                                 mdest->invert = true;
632                         }
633
634                         /* emit masquerading entries for non-negated addresses
635                            and ensure that both src and dest loops run at least once,
636                            even if there are no relevant addresses */
637                         for (first_src = true, msrc = NULL;
638                              (msrc = next_addr(msrc, &zone->masq_src,
639                                                    handle->family, false)) || first_src;
640                              first_src = false)
641                         {
642                                 for (first_dest = true, mdest = NULL;
643                                      (mdest = next_addr(mdest, &zone->masq_dest,
644                                                             handle->family, false)) || first_dest;
645                                      first_dest = false)
646                                 {
647                                         r = fw3_ipt_rule_new(handle);
648                                         fw3_ipt_rule_src_dest(r, msrc, mdest);
649                                         fw3_ipt_rule_target(r, "MASQUERADE");
650                                         fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name);
651                                 }
652                         }
653                 }
654                 break;
655
656         case FW3_TABLE_RAW:
657         case FW3_TABLE_MANGLE:
658                 break;
659         }
660
661         print_interface_rules(handle, state, reload, zone);
662 }
663
664 void
665 fw3_print_zone_chains(struct fw3_ipt_handle *handle, struct fw3_state *state,
666                       bool reload)
667 {
668         struct fw3_zone *zone;
669
670         list_for_each_entry(zone, &state->zones, list)
671                 print_zone_chain(handle, state, reload, zone);
672 }
673
674 void
675 fw3_print_zone_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
676                      bool reload)
677 {
678         struct fw3_zone *zone;
679
680         list_for_each_entry(zone, &state->zones, list)
681                 print_zone_rule(handle, state, reload, zone);
682 }
683
684 void
685 fw3_flush_zones(struct fw3_ipt_handle *handle, struct fw3_state *state,
686                 bool reload)
687 {
688         struct fw3_zone *z, *tmp;
689         const struct fw3_chain_spec *c;
690         char chain[32];
691
692         list_for_each_entry_safe(z, tmp, &state->zones, list)
693         {
694                 if (!has(z->flags, handle->family, handle->table))
695                         continue;
696
697                 for (c = zone_chains; c->format; c++)
698                 {
699                         /* don't touch user chains on selective stop */
700                         if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS)
701                                 continue;
702
703                         if (!fw3_is_family(c, handle->family))
704                                 continue;
705
706                         if (c->table != handle->table)
707                                 continue;
708
709                         if (c->flag && !has(z->flags, handle->family, c->flag))
710                                 continue;
711
712                         snprintf(chain, sizeof(chain), c->format, z->name);
713                         fw3_ipt_flush_chain(handle, chain);
714
715                         /* keep certain basic chains that do not depend on any settings to
716                            avoid purging unrelated user rules pointing to them */
717                         if (reload && !c->flag)
718                                 continue;
719
720                         fw3_ipt_delete_chain(handle, chain);
721                 }
722
723                 del(z->flags, handle->family, handle->table);
724         }
725 }
726
727 void
728 fw3_hotplug_zones(struct fw3_state *state, bool add)
729 {
730         struct fw3_zone *z;
731         struct fw3_device *d;
732
733         list_for_each_entry(z, &state->zones, list)
734         {
735                 if (add != fw3_hasbit(z->flags[0], FW3_FLAG_HOTPLUG))
736                 {
737                         list_for_each_entry(d, &z->devices, list)
738                                 fw3_hotplug(add, z, d);
739
740                         if (add)
741                                 fw3_setbit(z->flags[0], FW3_FLAG_HOTPLUG);
742                         else
743                                 fw3_delbit(z->flags[0], FW3_FLAG_HOTPLUG);
744                 }
745         }
746 }
747
748 struct fw3_zone *
749 fw3_lookup_zone(struct fw3_state *state, const char *name)
750 {
751         struct fw3_zone *z;
752
753         if (list_empty(&state->zones))
754                 return NULL;
755
756         list_for_each_entry(z, &state->zones, list)
757         {
758                 if (strcmp(z->name, name))
759                         continue;
760
761                 return z;
762         }
763
764         return NULL;
765 }
766
767 struct list_head *
768 fw3_resolve_zone_addresses(struct fw3_zone *zone, struct fw3_address *addr)
769 {
770         struct fw3_device *net;
771         struct fw3_address *cur, *tmp;
772         struct list_head *all;
773
774         all = calloc(1, sizeof(*all));
775         if (!all)
776                 return NULL;
777
778         INIT_LIST_HEAD(all);
779
780         if (addr && addr->set)
781         {
782                 tmp = malloc(sizeof(*tmp));
783
784                 if (tmp)
785                 {
786                         *tmp = *addr;
787                         list_add_tail(&tmp->list, all);
788                 }
789         }
790         else
791         {
792                 list_for_each_entry(net, &zone->networks, list)
793                         fw3_ubus_address(all, net->name);
794
795                 list_for_each_entry(cur, &zone->subnets, list)
796                 {
797                         tmp = malloc(sizeof(*tmp));
798
799                         if (!tmp)
800                                 continue;
801
802                         *tmp = *cur;
803                         list_add_tail(&tmp->list, all);
804                 }
805         }
806
807         return all;
808 }