iptables: fix regression with unintended free in need_protomatch
[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 #include "helpers.h"
22
23
24 #define C(f, tbl, tgt, fmt) \
25 { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_FLAG_##tgt, fmt }
26
27 static const struct fw3_chain_spec zone_chains[] = {
28 C(ANY, FILTER, UNSPEC, "zone_?_input"),
29 C(ANY, FILTER, UNSPEC, "zone_?_output"),
30 C(ANY, FILTER, UNSPEC, "zone_?_forward"),
31
32 C(ANY, FILTER, SRC_ACCEPT, "zone_?_src_ACCEPT"),
33 C(ANY, FILTER, SRC_REJECT, "zone_?_src_REJECT"),
34 C(ANY, FILTER, SRC_DROP, "zone_?_src_DROP"),
35
36 C(ANY, FILTER, ACCEPT, "zone_?_dest_ACCEPT"),
37 C(ANY, FILTER, REJECT, "zone_?_dest_REJECT"),
38 C(ANY, FILTER, DROP, "zone_?_dest_DROP"),
39
40 C(V4, NAT, SNAT, "zone_?_postrouting"),
41 C(V4, NAT, DNAT, "zone_?_prerouting"),
42
43 C(ANY, RAW, HELPER, "zone_?_helper"),
44 C(ANY, RAW, NOTRACK, "zone_?_notrack"),
45
46 C(ANY, FILTER, CUSTOM_CHAINS, "input_?_rule"),
47 C(ANY, FILTER, CUSTOM_CHAINS, "output_?_rule"),
48 C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_?_rule"),
49
50 C(V4, NAT, CUSTOM_CHAINS, "prerouting_?_rule"),
51 C(V4, NAT, CUSTOM_CHAINS, "postrouting_?_rule"),
52
53 { }
54 };
55
56 enum fw3_zone_logmask {
57 FW3_ZONE_LOG_FILTER = (1 << 0),
58 FW3_ZONE_LOG_MANGLE = (1 << 1),
59 };
60
61 const struct fw3_option fw3_zone_opts[] = {
62 FW3_OPT("enabled", bool, zone, enabled),
63
64 FW3_OPT("name", string, zone, name),
65 FW3_OPT("family", family, zone, family),
66
67 FW3_LIST("network", device, zone, networks),
68 FW3_LIST("device", device, zone, devices),
69 FW3_LIST("subnet", network, zone, subnets),
70
71 FW3_OPT("input", target, zone, policy_input),
72 FW3_OPT("forward", target, zone, policy_forward),
73 FW3_OPT("output", target, zone, policy_output),
74
75 FW3_OPT("masq", bool, zone, masq),
76 FW3_OPT("masq_allow_invalid", bool, zone, masq_allow_invalid),
77 FW3_LIST("masq_src", network, zone, masq_src),
78 FW3_LIST("masq_dest", network, zone, masq_dest),
79
80 FW3_OPT("extra", string, zone, extra_src),
81 FW3_OPT("extra_src", string, zone, extra_src),
82 FW3_OPT("extra_dest", string, zone, extra_dest),
83
84 FW3_OPT("mtu_fix", bool, zone, mtu_fix),
85 FW3_OPT("custom_chains", bool, zone, custom_chains),
86
87 FW3_OPT("log", int, zone, log),
88 FW3_OPT("log_limit", limit, zone, log_limit),
89
90 FW3_OPT("auto_helper", bool, zone, auto_helper),
91 FW3_LIST("helper", cthelper, zone, cthelpers),
92
93 FW3_OPT("__flags_v4", int, zone, flags[0]),
94 FW3_OPT("__flags_v6", int, zone, flags[1]),
95
96 FW3_LIST("__addrs", address, zone, old_addrs),
97
98 { }
99 };
100
101 static void
102 check_policy(struct uci_element *e, enum fw3_flag *pol, enum fw3_flag def,
103 const char *name)
104 {
105 if (*pol == FW3_FLAG_UNSPEC)
106 {
107 warn_elem(e, "has no %s policy specified, using default", name);
108 *pol = def;
109 }
110 else if (*pol > FW3_FLAG_DROP)
111 {
112 warn_elem(e, "has invalid %s policy, using default", name);
113 *pol = def;
114 }
115 }
116
117 static bool
118 check_masq_addrs(struct list_head *head)
119 {
120 struct fw3_address *addr;
121 int n_addr = 0, n_failed = 0;
122
123 list_for_each_entry(addr, head, list)
124 {
125 if (addr->invert)
126 continue;
127
128 n_addr++;
129
130 if (!addr->set && addr->resolved)
131 n_failed++;
132 }
133
134 return (n_addr == 0 || n_failed < n_addr);
135 }
136
137 static void
138 resolve_networks(struct uci_element *e, struct fw3_zone *zone)
139 {
140 struct fw3_device *net, *dev, *tmp;
141
142 list_for_each_entry(net, &zone->networks, list)
143 {
144 tmp = fw3_ubus_device(net->name);
145
146 if (!tmp)
147 {
148 warn_elem(e, "cannot resolve device of network '%s'", net->name);
149 continue;
150 }
151
152 list_for_each_entry(dev, &zone->devices, list)
153 if (!strcmp(dev->name, tmp->name))
154 goto alias;
155
156 snprintf(tmp->network, sizeof(tmp->network), "%s", net->name);
157 list_add_tail(&tmp->list, &zone->devices);
158 continue;
159 alias:
160 free(tmp);
161 }
162 }
163
164 static void
165 resolve_cthelpers(struct fw3_state *s, struct uci_element *e, struct fw3_zone *zone)
166 {
167 struct fw3_cthelpermatch *match;
168
169 if (list_empty(&zone->cthelpers))
170 {
171 if (!zone->masq && zone->auto_helper)
172 {
173 fw3_setbit(zone->flags[0], FW3_FLAG_HELPER);
174 fw3_setbit(zone->flags[1], FW3_FLAG_HELPER);
175 }
176
177 return;
178 }
179
180 list_for_each_entry(match, &zone->cthelpers, list)
181 {
182 if (match->invert)
183 {
184 warn_elem(e, "must not use a negated helper match");
185 continue;
186 }
187
188 match->ptr = fw3_lookup_cthelper(s, match->name);
189
190 if (!match->ptr)
191 {
192 warn_elem(e, "refers to not existing helper '%s'", match->name);
193 continue;
194 }
195
196 if (fw3_is_family(match->ptr, FW3_FAMILY_V4))
197 fw3_setbit(zone->flags[0], FW3_FLAG_HELPER);
198
199 if (fw3_is_family(match->ptr, FW3_FAMILY_V6))
200 fw3_setbit(zone->flags[1], FW3_FLAG_HELPER);
201 }
202 }
203
204 struct fw3_zone *
205 fw3_alloc_zone(void)
206 {
207 struct fw3_zone *zone;
208
209 zone = calloc(1, sizeof(*zone));
210 if (!zone)
211 return NULL;
212
213 INIT_LIST_HEAD(&zone->networks);
214 INIT_LIST_HEAD(&zone->devices);
215 INIT_LIST_HEAD(&zone->subnets);
216 INIT_LIST_HEAD(&zone->masq_src);
217 INIT_LIST_HEAD(&zone->masq_dest);
218 INIT_LIST_HEAD(&zone->cthelpers);
219
220 INIT_LIST_HEAD(&zone->old_addrs);
221
222 zone->enabled = true;
223 zone->auto_helper = true;
224 zone->custom_chains = true;
225 zone->log_limit.rate = 10;
226
227 return zone;
228 }
229
230 void
231 fw3_load_zones(struct fw3_state *state, struct uci_package *p)
232 {
233 struct uci_section *s;
234 struct uci_element *e;
235 struct fw3_zone *zone;
236 struct fw3_defaults *defs = &state->defaults;
237
238 INIT_LIST_HEAD(&state->zones);
239
240 uci_foreach_element(&p->sections, e)
241 {
242 s = uci_to_section(e);
243
244 if (strcmp(s->type, "zone"))
245 continue;
246
247 zone = fw3_alloc_zone();
248
249 if (!zone)
250 continue;
251
252 if (!fw3_parse_options(zone, fw3_zone_opts, s))
253 warn_elem(e, "has invalid options");
254
255 if (!zone->enabled)
256 {
257 fw3_free_zone(zone);
258 continue;
259 }
260
261 if (!zone->extra_dest)
262 zone->extra_dest = zone->extra_src;
263
264 if (!defs->custom_chains && zone->custom_chains)
265 zone->custom_chains = false;
266
267 if (!defs->auto_helper && zone->auto_helper)
268 zone->auto_helper = false;
269
270 if (!zone->name || !*zone->name)
271 {
272 warn_elem(e, "has no name - ignoring");
273 fw3_free_zone(zone);
274 continue;
275 }
276
277 if (strlen(zone->name) > FW3_ZONE_MAXNAMELEN)
278 {
279 warn_elem(e, "must not have a name longer than %u characters",
280 FW3_ZONE_MAXNAMELEN);
281 fw3_free_zone(zone);
282 continue;
283 }
284
285 fw3_ubus_zone_devices(zone);
286
287 if (list_empty(&zone->networks) && list_empty(&zone->devices) &&
288 list_empty(&zone->subnets) && !zone->extra_src)
289 {
290 warn_elem(e, "has no device, network, subnet or extra options");
291 }
292
293 if (!check_masq_addrs(&zone->masq_src))
294 {
295 warn_elem(e, "has unresolved masq_src, disabling masq");
296 zone->masq = false;
297 }
298
299 if (!check_masq_addrs(&zone->masq_dest))
300 {
301 warn_elem(e, "has unresolved masq_dest, disabling masq");
302 zone->masq = false;
303 }
304
305 check_policy(e, &zone->policy_input, defs->policy_input, "input");
306 check_policy(e, &zone->policy_output, defs->policy_output, "output");
307 check_policy(e, &zone->policy_forward, defs->policy_forward, "forward");
308
309 resolve_networks(e, zone);
310
311 if (zone->masq)
312 {
313 fw3_setbit(zone->flags[0], FW3_FLAG_SNAT);
314 }
315
316 if (zone->custom_chains)
317 {
318 fw3_setbit(zone->flags[0], FW3_FLAG_SNAT);
319 fw3_setbit(zone->flags[0], FW3_FLAG_DNAT);
320 }
321
322 resolve_cthelpers(state, e, zone);
323
324 fw3_setbit(zone->flags[0], fw3_to_src_target(zone->policy_input));
325 fw3_setbit(zone->flags[0], zone->policy_forward);
326 fw3_setbit(zone->flags[0], zone->policy_output);
327
328 fw3_setbit(zone->flags[1], fw3_to_src_target(zone->policy_input));
329 fw3_setbit(zone->flags[1], zone->policy_forward);
330 fw3_setbit(zone->flags[1], zone->policy_output);
331
332 list_add_tail(&zone->list, &state->zones);
333 }
334 }
335
336
337 static char *
338 format_chain(const char *fmt, const char *zonename)
339 {
340 static char chain[32];
341 size_t rem;
342 char *p;
343 int len;
344
345 for (p = chain, rem = sizeof(chain); *fmt; fmt++) {
346 if (*fmt == '?') {
347 len = snprintf(p, rem, "%s", zonename);
348
349 if (len < 0 || len >= rem)
350 break;
351
352 rem -= len;
353 p += len;
354 }
355 else {
356 if (rem <= 1)
357 break;
358
359 *p++ = *fmt;
360 rem--;
361 }
362 }
363
364 *p = 0;
365
366 return chain;
367 }
368
369 static void
370 print_zone_chain(struct fw3_ipt_handle *handle, struct fw3_state *state,
371 bool reload, struct fw3_zone *zone)
372 {
373 int i;
374 struct fw3_ipt_rule *r;
375 const struct fw3_chain_spec *c;
376
377 const char *flt_chains[] = {
378 "input", "input",
379 "output", "output",
380 "forward", "forwarding",
381 };
382
383 const char *nat_chains[] = {
384 "prerouting", "prerouting",
385 "postrouting", "postrouting",
386 };
387
388 if (!fw3_is_family(zone, handle->family))
389 return;
390
391 set(zone->flags, handle->family, handle->table);
392
393 if (zone->custom_chains)
394 set(zone->flags, handle->family, FW3_FLAG_CUSTOM_CHAINS);
395
396 for (c = zone_chains; c->format; c++)
397 {
398 if (!fw3_is_family(c, handle->family))
399 continue;
400
401 if (c->table != handle->table)
402 continue;
403
404 if (c->flag &&
405 !fw3_hasbit(zone->flags[handle->family == FW3_FAMILY_V6], c->flag))
406 continue;
407
408 fw3_ipt_create_chain(handle, reload, format_chain(c->format, zone->name));
409 }
410
411 if (zone->custom_chains)
412 {
413 if (handle->table == FW3_TABLE_FILTER)
414 {
415 for (i = 0; i < sizeof(flt_chains)/sizeof(flt_chains[0]); i += 2)
416 {
417 r = fw3_ipt_rule_new(handle);
418 fw3_ipt_rule_comment(r, "Custom %s %s rule chain", zone->name, flt_chains[i+1]);
419 fw3_ipt_rule_target(r, "%s_%s_rule", flt_chains[i+1], zone->name);
420 fw3_ipt_rule_append(r, "zone_%s_%s", zone->name, flt_chains[i]);
421 }
422 }
423 else if (handle->table == FW3_TABLE_NAT)
424 {
425 for (i = 0; i < sizeof(nat_chains)/sizeof(nat_chains[0]); i += 2)
426 {
427 r = fw3_ipt_rule_new(handle);
428 fw3_ipt_rule_comment(r, "Custom %s %s rule chain", zone->name, nat_chains[i+1]);
429 fw3_ipt_rule_target(r, "%s_%s_rule", nat_chains[i+1], zone->name);
430 fw3_ipt_rule_append(r, "zone_%s_%s", zone->name, nat_chains[i]);
431 }
432 }
433 }
434
435 set(zone->flags, handle->family, handle->table);
436 }
437
438 static void
439 print_interface_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
440 bool reload, struct fw3_zone *zone,
441 struct fw3_device *dev, struct fw3_address *sub)
442 {
443 struct fw3_protocol tcp = { .protocol = 6 };
444 struct fw3_ipt_rule *r;
445 enum fw3_flag t;
446
447 char buf[32];
448
449 int i;
450
451 const char *chains[] = {
452 "input", "INPUT",
453 "output", "OUTPUT",
454 "forward", "FORWARD",
455 };
456
457 #define jump_target(t) \
458 ((t == FW3_FLAG_REJECT) ? "reject" : fw3_flag_names[t])
459
460 if (handle->table == FW3_TABLE_FILTER)
461 {
462 for (t = FW3_FLAG_ACCEPT; t <= FW3_FLAG_DROP; t++)
463 {
464 if (t > FW3_FLAG_ACCEPT && zone->log & FW3_ZONE_LOG_FILTER)
465 {
466 if (has(zone->flags, handle->family, fw3_to_src_target(t)))
467 {
468 r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
469
470 snprintf(buf, sizeof(buf) - 1, "%s %s in: ",
471 fw3_flag_names[t], zone->name);
472
473 fw3_ipt_rule_limit(r, &zone->log_limit);
474 fw3_ipt_rule_target(r, "LOG");
475 fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
476 fw3_ipt_rule_replace(r, "zone_%s_src_%s",
477 zone->name, fw3_flag_names[t]);
478 }
479
480 if (has(zone->flags, handle->family, t))
481 {
482 r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
483
484 snprintf(buf, sizeof(buf) - 1, "%s %s out: ",
485 fw3_flag_names[t], zone->name);
486
487 fw3_ipt_rule_limit(r, &zone->log_limit);
488 fw3_ipt_rule_target(r, "LOG");
489 fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
490 fw3_ipt_rule_replace(r, "zone_%s_dest_%s",
491 zone->name, fw3_flag_names[t]);
492 }
493 }
494
495 if (has(zone->flags, handle->family, fw3_to_src_target(t)))
496 {
497 r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
498 fw3_ipt_rule_target(r, jump_target(t));
499 fw3_ipt_rule_extra(r, zone->extra_src);
500
501 if (t == FW3_FLAG_ACCEPT && !state->defaults.drop_invalid)
502 fw3_ipt_rule_extra(r,
503 "-m conntrack --ctstate NEW,UNTRACKED");
504
505 fw3_ipt_rule_replace(r, "zone_%s_src_%s", zone->name,
506 fw3_flag_names[t]);
507 }
508
509 if (has(zone->flags, handle->family, t))
510 {
511 if (t == FW3_FLAG_ACCEPT &&
512 zone->masq && !zone->masq_allow_invalid)
513 {
514 r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
515 fw3_ipt_rule_extra(r, "-m conntrack --ctstate INVALID");
516 fw3_ipt_rule_comment(r, "Prevent NAT leakage");
517 fw3_ipt_rule_target(r, fw3_flag_names[FW3_FLAG_DROP]);
518 fw3_ipt_rule_replace(r, "zone_%s_dest_%s", zone->name,
519 fw3_flag_names[t]);
520 }
521
522 r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
523 fw3_ipt_rule_target(r, jump_target(t));
524 fw3_ipt_rule_extra(r, zone->extra_dest);
525 fw3_ipt_rule_replace(r, "zone_%s_dest_%s", zone->name,
526 fw3_flag_names[t]);
527 }
528 }
529
530 for (i = 0; i < sizeof(chains)/sizeof(chains[0]); i += 2)
531 {
532 if (*chains[i] == 'o')
533 r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
534 else
535 r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
536
537 fw3_ipt_rule_target(r, "zone_%s_%s", zone->name, chains[i]);
538
539 if (*chains[i] == 'o')
540 fw3_ipt_rule_extra(r, zone->extra_dest);
541 else
542 fw3_ipt_rule_extra(r, zone->extra_src);
543
544 fw3_ipt_rule_replace(r, chains[i + 1]);
545 }
546 }
547 else if (handle->table == FW3_TABLE_NAT)
548 {
549 if (has(zone->flags, handle->family, FW3_FLAG_DNAT))
550 {
551 r = fw3_ipt_rule_create(handle, NULL, dev, NULL, sub, NULL);
552 fw3_ipt_rule_target(r, "zone_%s_prerouting", zone->name);
553 fw3_ipt_rule_extra(r, zone->extra_src);
554 fw3_ipt_rule_replace(r, "PREROUTING");
555 }
556
557 if (has(zone->flags, handle->family, FW3_FLAG_SNAT))
558 {
559 r = fw3_ipt_rule_create(handle, NULL, NULL, dev, NULL, sub);
560 fw3_ipt_rule_target(r, "zone_%s_postrouting", zone->name);
561 fw3_ipt_rule_extra(r, zone->extra_dest);
562 fw3_ipt_rule_replace(r, "POSTROUTING");
563 }
564 }
565 else if (handle->table == FW3_TABLE_MANGLE)
566 {
567 if (zone->mtu_fix)
568 {
569 if (zone->log & FW3_ZONE_LOG_MANGLE)
570 {
571 snprintf(buf, sizeof(buf) - 1, "MSSFIX %s out: ", zone->name);
572
573 r = fw3_ipt_rule_create(handle, &tcp, NULL, dev, NULL, sub);
574 fw3_ipt_rule_addarg(r, false, "--tcp-flags", "SYN,RST");
575 fw3_ipt_rule_addarg(r, false, "SYN", NULL);
576 fw3_ipt_rule_limit(r, &zone->log_limit);
577 fw3_ipt_rule_comment(r, "Zone %s MTU fix logging", zone->name);
578 fw3_ipt_rule_target(r, "LOG");
579 fw3_ipt_rule_addarg(r, false, "--log-prefix", buf);
580 fw3_ipt_rule_replace(r, "FORWARD");
581 }
582
583 r = fw3_ipt_rule_create(handle, &tcp, NULL, dev, NULL, sub);
584 fw3_ipt_rule_addarg(r, false, "--tcp-flags", "SYN,RST");
585 fw3_ipt_rule_addarg(r, false, "SYN", NULL);
586 fw3_ipt_rule_comment(r, "Zone %s MTU fixing", zone->name);
587 fw3_ipt_rule_target(r, "TCPMSS");
588 fw3_ipt_rule_addarg(r, false, "--clamp-mss-to-pmtu", NULL);
589 fw3_ipt_rule_replace(r, "FORWARD");
590
591 r = fw3_ipt_rule_create(handle, &tcp, dev, NULL, sub, NULL);
592 fw3_ipt_rule_addarg(r, false, "--tcp-flags", "SYN,RST");
593 fw3_ipt_rule_addarg(r, false, "SYN", NULL);
594 fw3_ipt_rule_comment(r, "Zone %s MTU fixing", zone->name);
595 fw3_ipt_rule_target(r, "TCPMSS");
596 fw3_ipt_rule_addarg(r, false, "--clamp-mss-to-pmtu", NULL);
597 fw3_ipt_rule_replace(r, "FORWARD");
598 }
599 }
600 else if (handle->table == FW3_TABLE_RAW)
601 {
602 bool loopback_dev = (dev != NULL && !dev->any &&
603 !dev->invert && fw3_check_loopback_dev(dev->name));
604 char *chain = loopback_dev || (sub != NULL && !sub->invert && fw3_check_loopback_addr(sub)) ?
605 "OUTPUT" : "PREROUTING";
606
607 if (has(zone->flags, handle->family, FW3_FLAG_HELPER))
608 {
609 r = fw3_ipt_rule_create(handle, NULL, loopback_dev ? NULL : dev, NULL, sub, NULL);
610 fw3_ipt_rule_comment(r, "%s CT helper assignment", zone->name);
611 fw3_ipt_rule_target(r, "zone_%s_helper", zone->name);
612 fw3_ipt_rule_extra(r, zone->extra_src);
613 fw3_ipt_rule_replace(r, chain);
614 }
615
616 if (has(zone->flags, handle->family, FW3_FLAG_NOTRACK))
617 {
618 r = fw3_ipt_rule_create(handle, NULL, loopback_dev ? NULL : dev, NULL, sub, NULL);
619 fw3_ipt_rule_comment(r, "%s CT bypass", zone->name);
620 fw3_ipt_rule_target(r, "zone_%s_notrack", zone->name);
621 fw3_ipt_rule_extra(r, zone->extra_src);
622 fw3_ipt_rule_replace(r, chain);
623 }
624 }
625 }
626
627 static void
628 print_interface_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
629 bool reload, struct fw3_zone *zone)
630 {
631 struct fw3_device *dev;
632 struct fw3_address *sub;
633
634 fw3_foreach(dev, &zone->devices)
635 fw3_foreach(sub, &zone->subnets)
636 {
637 if (!fw3_is_family(sub, handle->family))
638 continue;
639
640 if (!dev && !sub && !zone->extra_src && !zone->extra_dest)
641 continue;
642
643 print_interface_rule(handle, state, reload, zone, dev, sub);
644 }
645 }
646
647 static struct fw3_address *
648 next_addr(struct fw3_address *addr, struct list_head *list,
649 enum fw3_family family, bool invert)
650 {
651 struct list_head *p;
652 struct fw3_address *rv;
653
654 for (p = addr ? addr->list.next : list->next; p != list; p = p->next)
655 {
656 rv = list_entry(p, struct fw3_address, list);
657
658 if (fw3_is_family(rv, family) && rv->set && rv->invert == invert)
659 return rv;
660 }
661
662 return NULL;
663 }
664
665 static void
666 print_zone_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
667 bool reload, struct fw3_zone *zone)
668 {
669 bool first_src, first_dest;
670 struct fw3_address *msrc;
671 struct fw3_address *mdest;
672 struct fw3_ipt_rule *r;
673
674 if (!fw3_is_family(zone, handle->family))
675 return;
676
677 info(" * Zone '%s'", zone->name);
678
679 switch (handle->table)
680 {
681 case FW3_TABLE_FILTER:
682 if (has(zone->flags, handle->family, FW3_FLAG_DNAT))
683 {
684 r = fw3_ipt_rule_new(handle);
685 fw3_ipt_rule_extra(r, "-m conntrack --ctstate DNAT");
686 fw3_ipt_rule_comment(r, "Accept port redirections");
687 fw3_ipt_rule_target(r, fw3_flag_names[FW3_FLAG_ACCEPT]);
688 fw3_ipt_rule_append(r, "zone_%s_input", zone->name);
689
690 r = fw3_ipt_rule_new(handle);
691 fw3_ipt_rule_extra(r, "-m conntrack --ctstate DNAT");
692 fw3_ipt_rule_comment(r, "Accept port forwards");
693 fw3_ipt_rule_target(r, fw3_flag_names[FW3_FLAG_ACCEPT]);
694 fw3_ipt_rule_append(r, "zone_%s_forward", zone->name);
695 }
696
697 r = fw3_ipt_rule_new(handle);
698 fw3_ipt_rule_target(r, "zone_%s_src_%s", zone->name,
699 fw3_flag_names[zone->policy_input]);
700 fw3_ipt_rule_append(r, "zone_%s_input", zone->name);
701
702 r = fw3_ipt_rule_new(handle);
703 fw3_ipt_rule_target(r, "zone_%s_dest_%s", zone->name,
704 fw3_flag_names[zone->policy_forward]);
705 fw3_ipt_rule_append(r, "zone_%s_forward", zone->name);
706
707 r = fw3_ipt_rule_new(handle);
708 fw3_ipt_rule_target(r, "zone_%s_dest_%s", zone->name,
709 fw3_flag_names[zone->policy_output]);
710 fw3_ipt_rule_append(r, "zone_%s_output", zone->name);
711
712 break;
713
714 case FW3_TABLE_NAT:
715 if (zone->masq && handle->family == FW3_FAMILY_V4)
716 {
717 /* for any negated masq_src ip, emit -s addr -j RETURN rules */
718 for (msrc = NULL;
719 (msrc = next_addr(msrc, &zone->masq_src,
720 handle->family, true)) != NULL; )
721 {
722 msrc->invert = false;
723 r = fw3_ipt_rule_new(handle);
724 fw3_ipt_rule_src_dest(r, msrc, NULL);
725 fw3_ipt_rule_target(r, "RETURN");
726 fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name);
727 msrc->invert = true;
728 }
729
730 /* for any negated masq_dest ip, emit -d addr -j RETURN rules */
731 for (mdest = NULL;
732 (mdest = next_addr(mdest, &zone->masq_dest,
733 handle->family, true)) != NULL; )
734 {
735 mdest->invert = false;
736 r = fw3_ipt_rule_new(handle);
737 fw3_ipt_rule_src_dest(r, NULL, mdest);
738 fw3_ipt_rule_target(r, "RETURN");
739 fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name);
740 mdest->invert = true;
741 }
742
743 /* emit masquerading entries for non-negated addresses
744 and ensure that both src and dest loops run at least once,
745 even if there are no relevant addresses */
746 for (first_src = true, msrc = NULL;
747 (msrc = next_addr(msrc, &zone->masq_src,
748 handle->family, false)) || first_src;
749 first_src = false)
750 {
751 for (first_dest = true, mdest = NULL;
752 (mdest = next_addr(mdest, &zone->masq_dest,
753 handle->family, false)) || first_dest;
754 first_dest = false)
755 {
756 r = fw3_ipt_rule_new(handle);
757 fw3_ipt_rule_src_dest(r, msrc, mdest);
758 fw3_ipt_rule_target(r, "MASQUERADE");
759 fw3_ipt_rule_append(r, "zone_%s_postrouting", zone->name);
760 }
761 }
762 }
763 break;
764
765 case FW3_TABLE_RAW:
766 fw3_print_cthelpers(handle, state, zone);
767 break;
768
769 case FW3_TABLE_MANGLE:
770 break;
771 }
772
773 print_interface_rules(handle, state, reload, zone);
774 }
775
776 void
777 fw3_print_zone_chains(struct fw3_ipt_handle *handle, struct fw3_state *state,
778 bool reload)
779 {
780 struct fw3_zone *zone;
781
782 list_for_each_entry(zone, &state->zones, list)
783 print_zone_chain(handle, state, reload, zone);
784 }
785
786 void
787 fw3_print_zone_rules(struct fw3_ipt_handle *handle, struct fw3_state *state,
788 bool reload)
789 {
790 struct fw3_zone *zone;
791
792 list_for_each_entry(zone, &state->zones, list)
793 print_zone_rule(handle, state, reload, zone);
794 }
795
796 void
797 fw3_flush_zones(struct fw3_ipt_handle *handle, struct fw3_state *state,
798 bool reload)
799 {
800 struct fw3_zone *z, *tmp;
801 const struct fw3_chain_spec *c;
802
803 list_for_each_entry_safe(z, tmp, &state->zones, list)
804 {
805 if (!has(z->flags, handle->family, handle->table))
806 continue;
807
808 /* first flush all rules ... */
809 for (c = zone_chains; c->format; c++)
810 {
811 /* don't touch user chains on selective stop */
812 if (reload && c->flag == FW3_FLAG_CUSTOM_CHAINS)
813 continue;
814
815 if (!fw3_is_family(c, handle->family))
816 continue;
817
818 if (c->table != handle->table)
819 continue;
820
821 if (c->flag && !has(z->flags, handle->family, c->flag))
822 continue;
823
824 fw3_ipt_flush_chain(handle, format_chain(c->format, z->name));
825 }
826
827 /* ... then remove the chains */
828 for (c = zone_chains; c->format; c++)
829 {
830 if (!fw3_is_family(c, handle->family))
831 continue;
832
833 if (c->table != handle->table)
834 continue;
835
836 if (c->flag && !has(z->flags, handle->family, c->flag))
837 continue;
838
839 fw3_ipt_delete_chain(handle, reload,
840 format_chain(c->format, z->name));
841 }
842
843 del(z->flags, handle->family, handle->table);
844 }
845 }
846
847 void
848 fw3_hotplug_zones(struct fw3_state *state, bool add)
849 {
850 struct fw3_zone *z;
851 struct fw3_device *d;
852
853 list_for_each_entry(z, &state->zones, list)
854 {
855 if (add != fw3_hasbit(z->flags[0], FW3_FLAG_HOTPLUG))
856 {
857 list_for_each_entry(d, &z->devices, list)
858 fw3_hotplug(add, z, d);
859
860 if (add)
861 fw3_setbit(z->flags[0], FW3_FLAG_HOTPLUG);
862 else
863 fw3_delbit(z->flags[0], FW3_FLAG_HOTPLUG);
864 }
865 }
866 }
867
868 struct fw3_zone *
869 fw3_lookup_zone(struct fw3_state *state, const char *name)
870 {
871 struct fw3_zone *z;
872
873 if (list_empty(&state->zones))
874 return NULL;
875
876 list_for_each_entry(z, &state->zones, list)
877 {
878 if (strcmp(z->name, name))
879 continue;
880
881 return z;
882 }
883
884 return NULL;
885 }
886
887 struct list_head *
888 fw3_resolve_zone_addresses(struct fw3_zone *zone, struct fw3_address *addr)
889 {
890 struct fw3_device *net;
891 struct fw3_address *cur, *tmp;
892 struct list_head *all;
893
894 all = calloc(1, sizeof(*all));
895 if (!all)
896 return NULL;
897
898 INIT_LIST_HEAD(all);
899
900 if (addr && addr->set)
901 {
902 tmp = malloc(sizeof(*tmp));
903
904 if (tmp)
905 {
906 *tmp = *addr;
907 list_add_tail(&tmp->list, all);
908 }
909 }
910 else
911 {
912 list_for_each_entry(net, &zone->networks, list)
913 fw3_ubus_address(all, net->name);
914
915 list_for_each_entry(cur, &zone->subnets, list)
916 {
917 tmp = malloc(sizeof(*tmp));
918
919 if (!tmp)
920 continue;
921
922 *tmp = *cur;
923 list_add_tail(&tmp->list, all);
924 }
925 }
926
927 return all;
928 }