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