contrib/fwd: simplify ruleset, initial xtables integration
[project/luci.git] / contrib / fwd / src / fwd_rules.c
1 /*
2 * fwd - OpenWrt firewall daemon - iptables rule set
3 *
4 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * The fwd program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * The fwd program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with the fwd program. If not, see http://www.gnu.org/licenses/.
17 */
18
19
20 #include "fwd.h"
21 #include "fwd_addr.h"
22 #include "fwd_rules.h"
23 #include "fwd_xtables.h"
24
25 static void
26 fwd_ipt_rule_append(struct fwd_ipt_rulebuf *r, const char *fmt, ...)
27 {
28 int len = 0;
29 char buf[256]; buf[0] = 0;
30
31 va_list ap;
32 va_start(ap, fmt);
33 len = vsnprintf(buf, sizeof(buf), fmt, ap);
34 va_end(ap);
35
36 if( len > 0 )
37 {
38 r->buf = realloc(r->buf, r->len + len + 1);
39 memcpy(&r->buf[r->len], buf, len);
40 r->buf[r->len + len] = 0;
41 r->len += len;
42 }
43 }
44
45 static struct fwd_ipt_rulebuf * fwd_ipt_init(const char *table)
46 {
47 struct fwd_ipt_rulebuf *r;
48
49 if( (r = fwd_alloc_ptr(struct fwd_ipt_rulebuf)) != NULL )
50 {
51 fwd_ipt_rule_append(r, IPT " -t %s", table);
52 return r;
53 }
54
55 return NULL;
56 }
57
58 static void fwd_ipt_add_srcport(
59 struct fwd_ipt_rulebuf *r, struct fwd_portrange *p
60 ) {
61 if( p != NULL )
62 {
63 if( p->min < p->max )
64 fwd_ipt_rule_append(r, " --sport %u:%u", p->min, p->max);
65 else
66 fwd_ipt_rule_append(r, " --sport %u", p->min);
67 }
68 }
69
70 static void fwd_ipt_add_destport(
71 struct fwd_ipt_rulebuf *r, struct fwd_portrange *p
72 ) {
73 if( p != NULL )
74 {
75 if( p->min < p->max )
76 fwd_ipt_rule_append(r, " --dport %u:%u", p->min, p->max);
77 else
78 fwd_ipt_rule_append(r, " --dport %u", p->min);
79 }
80 }
81
82 static void fwd_ipt_add_proto(
83 struct fwd_ipt_rulebuf *r, struct fwd_proto *p
84 ) {
85 if( p != NULL )
86 {
87 switch( p->type )
88 {
89 case FWD_PR_TCPUDP:
90 fwd_ipt_rule_append(r, " -p tcp -p udp");
91 break;
92
93 case FWD_PR_TCP:
94 fwd_ipt_rule_append(r, " -p tcp");
95 break;
96
97 case FWD_PR_UDP:
98 fwd_ipt_rule_append(r, " -p udp");
99 break;
100
101 case FWD_PR_ICMP:
102 fwd_ipt_rule_append(r, " -p icmp");
103 break;
104
105 case FWD_PR_ALL:
106 fwd_ipt_rule_append(r, " -p all");
107 break;
108
109 case FWD_PR_CUSTOM:
110 fwd_ipt_rule_append(r, " -p %u", p->proto);
111 break;
112 }
113 }
114 }
115
116 static void fwd_ipt_add_srcaddr(
117 struct fwd_ipt_rulebuf *r, struct fwd_cidr *c
118 ) {
119 if( c != NULL )
120 {
121 if( c->prefix < 32 )
122 fwd_ipt_rule_append(r, " -s %s/%u",
123 inet_ntoa(c->addr), c->prefix);
124 else
125 fwd_ipt_rule_append(r, " -s %s", inet_ntoa(c->addr));
126 }
127 }
128
129 static void fwd_ipt_add_destaddr(
130 struct fwd_ipt_rulebuf *r, struct fwd_cidr *c
131 ) {
132 if( c != NULL )
133 {
134 if( c->prefix < 32 )
135 fwd_ipt_rule_append(r, " -d %s/%u",
136 inet_ntoa(c->addr), c->prefix);
137 else
138 fwd_ipt_rule_append(r, " -d %s", inet_ntoa(c->addr));
139 }
140 }
141
142 static void fwd_ipt_add_srcmac(
143 struct fwd_ipt_rulebuf *r, struct fwd_mac *m
144 ) {
145 if( m != NULL )
146 {
147 fwd_ipt_rule_append(r,
148 " -m mac --mac-source %02x:%02x:%02x:%02x:%02x:%02x",
149 m->mac[0], m->mac[1], m->mac[2],
150 m->mac[3], m->mac[4], m->mac[5]);
151 }
152 }
153
154 static void fwd_ipt_add_icmptype(
155 struct fwd_ipt_rulebuf *r, struct fwd_icmptype *i
156 ) {
157 if( i != NULL )
158 {
159 if( i->name )
160 fwd_ipt_rule_append(r, " --icmp-type %s", i->name);
161 else if( i->code > -1 )
162 fwd_ipt_rule_append(r, " --icmp-type %u/%u", i->type, i->code);
163 else
164 fwd_ipt_rule_append(r, " --icmp-type %u", i->type);
165 }
166 }
167
168 static void fwd_ipt_add_dnat_target(
169 struct fwd_ipt_rulebuf *r, struct fwd_cidr *c, struct fwd_portrange *p
170 ) {
171 if( c != NULL )
172 {
173 fwd_ipt_rule_append(r, " -j DNAT --to-destination %s",
174 inet_ntoa(c->addr));
175
176 if( (p != NULL) && (p->min < p->max) )
177 fwd_ipt_rule_append(r, ":%u-%u", p->min, p->max);
178 else if( p != NULL )
179 fwd_ipt_rule_append(r, ":%u", p->min);
180 }
181 }
182
183 static void fwd_ipt_add_policy_target(
184 struct fwd_ipt_rulebuf *r, enum fwd_policy p
185 ) {
186 fwd_ipt_rule_append(r, " -j %s",
187 (p == FWD_P_ACCEPT)
188 ? "handle_accept"
189 : (p == FWD_P_REJECT)
190 ? "handle_reject"
191 : "handle_drop"
192 );
193 }
194
195 static void fwd_ipt_add_comment(
196 struct fwd_ipt_rulebuf *r, const char *t, struct fwd_zone *z,
197 struct fwd_network_list *n, struct fwd_network_list *n2
198 ) {
199 if( (n != NULL) && (n2 != NULL) )
200 fwd_ipt_add_format(r, " -m comment --comment '%s:%s src:%s dest:%s'",
201 t, z->name, n->name, n2->name);
202 else if( (n == NULL) && (n2 != NULL) )
203 fwd_ipt_add_format(r, " -m comment --comment '%s:%s dest:%s'",
204 t, z->name, n2->name);
205 else
206 fwd_ipt_add_format(r, " -m comment --comment '%s:%s src:%s'",
207 t, z->name, n->name);
208 }
209
210 static void fwd_ipt_exec(struct fwd_ipt_rulebuf *r)
211 {
212 if( r->len )
213 printf("%s\n", r->buf);
214
215 fwd_free_ptr(r->buf);
216 fwd_free_ptr(r);
217 }
218
219 /* -P <chain> <policy> */
220 static void fwd_r_set_policy(
221 struct iptc_handle *h, const char *chain, const char *policy
222 ) {
223 iptc_set_policy(chain, policy, NULL, h);
224 }
225
226 /* -N <chain> */
227 static void fwd_r_new_chain(struct iptc_handle *h, const char *chain)
228 {
229 iptc_create_chain(chain, h);
230 }
231
232 /* -A <chain1> -j <chain2> */
233 static void fwd_r_jump_chain(
234 struct iptc_handle *h, const char *chain1, const char *chain2
235 ) {
236 struct fwd_xt_rule *r;
237
238 if( (r = fwd_xt_init_rule(h)) != NULL )
239 {
240 fwd_xt_get_target(r, chain2);
241 fwd_xt_exec_rule(r, chain1);
242 }
243 }
244
245 /* -A <chain> -m state --state INVALID -j DROP */
246 static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain)
247 {
248 struct fwd_xt_rule *r;
249 struct xtables_match *m;
250
251 if( (r = fwd_xt_init_rule(h)) != NULL )
252 {
253 if( (m = fwd_xt_get_match(r, "state")) != NULL )
254 {
255 fwd_xt_parse_match(r, m, "--state", "INVALID", 0);
256 fwd_xt_get_target(r, "DROP");
257 fwd_xt_exec_rule(r, chain);
258 }
259 }
260 }
261
262 /* -A <chain> -m state --state RELATED,ESTABLISHED -j ACCEPT */
263 static void fwd_r_accept_related(struct iptc_handle *h, const char *chain)
264 {
265 struct fwd_xt_rule *r;
266 struct xtables_match *m;
267
268 if( (r = fwd_xt_init_rule(h)) != NULL )
269 {
270 if( (m = fwd_xt_get_match(r, "state")) != NULL )
271 {
272 fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED", 0);
273 fwd_xt_get_target(r, "ACCEPT");
274 fwd_xt_exec_rule(r, chain);
275 }
276 }
277 }
278
279 /* -A INPUT -i lo -j ACCEPT; -A OUTPUT -o lo -j ACCEPT */
280 static void fwd_r_accept_lo(struct iptc_handle *h)
281 {
282 struct fwd_network_list n;
283 struct fwd_xt_rule *r;
284
285 n.ifname = "lo";
286
287 if( (r = fwd_xt_init_rule(h)) != NULL )
288 {
289 fwd_xt_parse_in(r, &n, 0);
290 fwd_xt_get_target(r, "ACCEPT");
291 fwd_xt_exec_rule(r, "INPUT");
292 }
293
294 if( (r = fwd_xt_init_rule(h)) != NULL )
295 {
296 fwd_xt_parse_out(r, &n, 0);
297 fwd_xt_get_target(r, "ACCEPT");
298 fwd_xt_exec_rule(r, "OUTPUT");
299 }
300 }
301
302 /* build syn_flood chain and jump rule */
303 static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def)
304 {
305 struct fwd_proto p;
306 struct fwd_xt_rule *r;
307 struct xtables_match *m;
308 char buf[32];
309
310 /* -N syn_flood */
311 fwd_r_new_chain(h, "syn_flood");
312
313 /* return rule */
314 if( (r = fwd_xt_init_rule(h)) != NULL )
315 {
316 /* -p tcp */
317 p.type = FWD_PR_TCP;
318 fwd_xt_parse_proto(r, &p, 0);
319
320 /* -m tcp --syn */
321 if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
322 {
323 fwd_xt_parse_match(r, m, "--syn", NULL, 0);
324 }
325
326 /* -m limit --limit x/second --limit-burst y */
327 if( (m = fwd_xt_get_match(r, "limit")) != NULL )
328 {
329 sprintf(buf, "%i/second", def->syn_rate);
330 fwd_xt_parse_match(r, m, "--limit", buf, 0);
331
332 sprintf(buf, "%i", def->syn_burst);
333 fwd_xt_parse_match(r, m, "--limit-burst", buf, 0);
334 }
335
336 /* -j RETURN; -A syn_flood */
337 fwd_xt_get_target(r, "RETURN");
338 fwd_xt_exec_rule(r, "syn_flood");
339 }
340
341 /* drop rule */
342 if( (r = fwd_xt_init_rule(h)) != NULL )
343 {
344 /* -j DROP; -A syn_flood */
345 fwd_xt_get_target(r, "DROP");
346 fwd_xt_exec_rule(r, "syn_flood");
347 }
348
349 /* jump to syn_flood rule */
350 if( (r = fwd_xt_init_rule(h)) != NULL )
351 {
352 /* -p tcp */
353 p.type = FWD_PR_TCP;
354 fwd_xt_parse_proto(r, &p, 0);
355
356 /* -m tcp --syn */
357 if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
358 {
359 fwd_xt_parse_match(r, m, "--syn", NULL, 0);
360 }
361
362 /* -j syn_flood; -A INPUT */
363 fwd_xt_get_target(r, "syn_flood");
364 fwd_xt_exec_rule(r, "INPUT");
365 }
366 }
367
368 /* build reject target chain */
369 static void fwd_r_handle_reject(struct iptc_handle *h)
370 {
371 struct fwd_proto p;
372 struct fwd_xt_rule *r;
373 struct xtables_target *t;
374
375 /* -N handle_reject */
376 fwd_r_new_chain(h, "handle_reject");
377
378 /* tcp reject rule */
379 if( (r = fwd_xt_init_rule(h)) != NULL )
380 {
381 /* -p tcp */
382 p.type = FWD_PR_TCP;
383 fwd_xt_parse_proto(r, &p, 0);
384
385 /* -j REJECT --reject-with tcp-reset */
386 if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
387 {
388 fwd_xt_parse_target(r, t, "--reject-with", "tcp-reset", 0);
389 }
390
391 /* -A handle_reject */
392 fwd_xt_exec_rule(r, "handle_reject");
393 }
394
395 /* common reject rule */
396 if( (r = fwd_xt_init_rule(h)) != NULL )
397 {
398 /* -j REJECT --reject-with icmp-port-unreachable */
399 if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
400 {
401 fwd_xt_parse_target(r, t, "--reject-with",
402 "icmp-port-unreachable", 0);
403 }
404
405 /* -A handle_reject */
406 fwd_xt_exec_rule(r, "handle_reject");
407 }
408 }
409
410 /* build drop target chain */
411 static void fwd_r_handle_drop(struct iptc_handle *h)
412 {
413 struct fwd_xt_rule *r;
414
415 /* -N handle_drop */
416 fwd_r_new_chain(h, "handle_drop");
417
418 /* common drop rule */
419 if( (r = fwd_xt_init_rule(h)) != NULL )
420 {
421 /* -j DROP; -A handle_reject */
422 fwd_xt_get_target(r, "DROP");
423 fwd_xt_exec_rule(r, "handle_reject");
424 }
425 }
426
427 /* build accept target chain */
428 static void fwd_r_handle_accept(struct iptc_handle *h)
429 {
430 struct fwd_xt_rule *r;
431
432 /* -N handle_accept */
433 fwd_r_new_chain(h, "handle_accept");
434
435 /* common accept rule */
436 if( (r = fwd_xt_init_rule(h)) != NULL )
437 {
438 /* -j ACCEPT; -A handle_accept */
439 fwd_xt_get_target(r, "ACCEPT");
440 fwd_xt_exec_rule(r, "handle_accept");
441 }
442 }
443
444
445 static void fwd_ipt_defaults_create(struct fwd_data *d)
446 {
447 struct fwd_defaults *def = &d->section.defaults;
448 struct iptc_handle *h_filter, *h_nat;
449
450 if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
451 fwd_fatal("Unable to obtain libiptc handle");
452
453 /* policies */
454 fwd_r_set_policy(h_filter, "INPUT",
455 def->input == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
456 fwd_r_set_policy(h_filter, "OUTPUT",
457 def->output == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
458 fwd_r_set_policy(h_filter, "FORWARD",
459 def->forward == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
460
461 /* invalid state drop */
462 if( def->drop_invalid )
463 {
464 fwd_r_drop_invalid(h_filter, "INPUT");
465 fwd_r_drop_invalid(h_filter, "OUTPUT");
466 fwd_r_drop_invalid(h_filter, "FORWARD");
467 }
468
469 /* default accept related */
470 fwd_r_accept_related(h_filter, "INPUT");
471 fwd_r_accept_related(h_filter, "OUTPUT");
472 fwd_r_accept_related(h_filter, "FORWARD");
473
474 /* default accept on lo */
475 fwd_r_accept_lo(h_filter);
476
477 /* syn flood protection */
478 if( def->syn_flood )
479 {
480 fwd_r_add_synflood(h_filter, def);
481 }
482
483 /* rule container chains */
484 fwd_r_new_chain(h_filter, "mssfix");
485 fwd_r_new_chain(h_filter, "zones");
486 fwd_r_new_chain(h_filter, "rules");
487 fwd_r_new_chain(h_filter, "redirects");
488 fwd_r_new_chain(h_filter, "forwardings");
489 fwd_r_jump_chain(h_filter, "INPUT", "rules");
490 fwd_r_jump_chain(h_filter, "FORWARD", "mssfix");
491 fwd_r_jump_chain(h_filter, "FORWARD", "zones");
492 fwd_r_jump_chain(h_filter, "FORWARD", "rules");
493 fwd_r_jump_chain(h_filter, "FORWARD", "redirects");
494 fwd_r_jump_chain(h_filter, "FORWARD", "forwardings");
495 fwd_r_new_chain(h_nat, "zonemasq");
496 fwd_r_new_chain(h_nat, "redirects");
497 fwd_r_jump_chain(h_nat, "POSTROUTING", "zonemasq");
498 fwd_r_jump_chain(h_nat, "PREROUTING", "redirects");
499 fwd_r_jump_chain(h_nat, "POSTROUTING", "redirects");
500
501 /* standard drop, accept, reject chain */
502 fwd_r_handle_drop(h_filter);
503 fwd_r_handle_accept(h_filter);
504 fwd_r_handle_reject(h_filter);
505
506
507 if( !iptc_commit(h_nat) )
508 fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
509
510 if( !iptc_commit(h_filter) )
511 fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
512
513 iptc_free(h_nat);
514 iptc_free(h_filter);
515 }
516
517
518 void fwd_ipt_build_ruleset(struct fwd_handle *h)
519 {
520 struct fwd_data *e;
521
522 fwd_xt_init();
523
524 for( e = h->conf; e; e = e->next )
525 {
526 switch(e->type)
527 {
528 case FWD_S_DEFAULTS:
529 printf("\n## DEFAULTS\n");
530 fwd_ipt_defaults_create(e);
531 break;
532
533 case FWD_S_INCLUDE:
534 printf("\n## INCLUDE %s\n", e->section.include.path);
535 break;
536
537 case FWD_S_ZONE:
538 case FWD_S_FORWARD:
539 case FWD_S_REDIRECT:
540 case FWD_S_RULE:
541 /* Make gcc happy */
542 break;
543 }
544 }
545 }
546
547
548 static struct fwd_zone *
549 fwd_lookup_zone(struct fwd_handle *h, const char *net)
550 {
551 struct fwd_data *e;
552 struct fwd_network_list *n;
553
554 for( e = h->conf; e; e = e->next )
555 if( e->type == FWD_S_ZONE )
556 for( n = e->section.zone.networks; n; n = n->next )
557 if( !strcmp(n->name, net) )
558 return &e->section.zone;
559
560 return NULL;
561 }
562
563 static struct fwd_network_list *
564 fwd_lookup_network(struct fwd_zone *z, const char *net)
565 {
566 struct fwd_network_list *n;
567
568 for( n = z->networks; n; n = n->next )
569 if( !strcmp(n->name, net) )
570 return n;
571
572 return NULL;
573 }
574
575 static struct fwd_addr_list *
576 fwd_lookup_addr(struct fwd_handle *h, struct fwd_network_list *n)
577 {
578 struct fwd_addr_list *a;
579
580 if( n != NULL )
581 for( a = h->addrs; a; a = a->next )
582 if( !strcmp(a->ifname, n->ifname) )
583 return a;
584
585 return NULL;
586 }
587
588 void fwd_ipt_addif(struct fwd_handle *h, const char *net)
589 {
590 struct fwd_data *e;
591 struct fwd_zone *z;
592 struct fwd_ipt_rulebuf *b;
593 struct fwd_rule *c;
594 struct fwd_redirect *r;
595 struct fwd_forwarding *f;
596 struct fwd_addr_list *a, *a2;
597 struct fwd_network_list *n, *n2;
598
599 if( !(z = fwd_lookup_zone(h, net)) )
600 return;
601
602 if( !(n = fwd_lookup_network(z, net)) )
603 return;
604
605 if( !(a = fwd_lookup_addr(h, n)) )
606 return;
607
608 printf("\n\n#\n# addif(%s)\n#\n", net);
609
610 /* Build masquerading rule */
611 if( z->masq )
612 {
613 printf("\n# Net %s (%s) - masq\n", n->name, n->ifname);
614
615 b = fwd_ipt_init("nat");
616 fwd_ipt_add_format(b, " -A zonemasq -o %s -j MASQUERADE", n->ifname);
617 fwd_ipt_add_comment(b, "masq", z, NULL, n);
618 fwd_ipt_exec(b);
619 }
620
621 /* Build MSS fix rule */
622 if( z->mtu_fix )
623 {
624 printf("\n# Net %s (%s) - mtu_fix\n", n->name, n->ifname);
625
626 b = fwd_ipt_init("filter");
627 fwd_ipt_add_format(b,
628 " -A mssfix -o %s -p tcp --tcp-flags SYN,RST SYN"
629 " -j TCPMSS --clamp-mss-to-pmtu", n->ifname);
630 fwd_ipt_add_comment(b, "mssfix", z, NULL, n);
631 fwd_ipt_exec(b);
632 }
633
634 /* Build intra-zone forwarding rules */
635 for( n2 = z->networks; n2; n2 = n2->next )
636 {
637 if( (a2 = fwd_lookup_addr(h, n2)) != NULL )
638 {
639 printf("\n# Net %s (%s) - intra-zone-forwarding"
640 " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n",
641 n->name, n->ifname, z->name, n->name, n->ifname,
642 z->name, n2->name, n2->ifname);
643
644 b = fwd_ipt_init("filter");
645 fwd_ipt_add_format(b, " -A zones -i %s -o %s",
646 n->ifname, n2->ifname);
647 fwd_ipt_add_policy_target(b, z->forward);
648 fwd_ipt_add_comment(b, "zone", z, n, n2);
649 fwd_ipt_exec(b);
650 }
651 }
652
653 /* Build inter-zone forwarding rules */
654 for( e = z->forwardings; e && (f = &e->section.forwarding); e = e->next )
655 {
656 for( n2 = f->dest->networks; n2; n2 = n2->next )
657 {
658 printf("\n# Net %s (%s) - inter-zone-forwarding"
659 " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n",
660 n->name, n->ifname, z->name, n->name, n->ifname,
661 f->dest->name, n2->name, n2->ifname);
662
663 /* Build forwarding rule */
664 b = fwd_ipt_init("filter");
665 fwd_ipt_add_format(b, " -A forwardings -i %s -o %s",
666 n->ifname, n2->ifname);
667 fwd_ipt_add_policy_target(b, FWD_P_ACCEPT);
668 fwd_ipt_add_comment(b, "forward", z, n, n2);
669 fwd_ipt_exec(b);
670 }
671 }
672
673 /* Build DNAT rules */
674 for( e = z->redirects; e && (r = &e->section.redirect); e = e->next )
675 {
676 printf("\n# Net %s (%s) - redirect Z:%s N:%s I:%s\n",
677 n->name, n->ifname, z->name, n->name, n->ifname);
678
679 /* DNAT */
680 b = fwd_ipt_init("nat");
681 fwd_ipt_add_format(b, " -A redirects -i %s -d %s",
682 n->ifname, inet_ntoa(a->ipaddr.v4));
683 fwd_ipt_add_proto(b, r->proto);
684 fwd_ipt_add_srcaddr(b, r->src_ip);
685 fwd_ipt_add_srcport(b, r->src_port);
686 fwd_ipt_add_destport(b, r->src_dport);
687 fwd_ipt_add_srcmac(b, r->src_mac);
688 fwd_ipt_add_dnat_target(b, r->dest_ip, r->dest_port);
689 fwd_ipt_add_comment(b, "redir", z, n, NULL);
690 fwd_ipt_exec(b);
691
692 /* Forward */
693 b = fwd_ipt_init("filter");
694 fwd_ipt_add_format(b, " -A redirects -i %s", n->ifname);
695 fwd_ipt_add_proto(b, r->proto);
696 fwd_ipt_add_srcmac(b, r->src_mac);
697 fwd_ipt_add_srcaddr(b, r->src_ip);
698 fwd_ipt_add_srcport(b, r->src_port);
699 fwd_ipt_add_destaddr(b, r->dest_ip);
700 fwd_ipt_add_destport(b, r->dest_port);
701 fwd_ipt_add_policy_target(b, FWD_P_ACCEPT);
702 fwd_ipt_add_comment(b, "redir", z, n, NULL);
703 fwd_ipt_exec(b);
704
705 /* Add loopback rule if neither src_ip nor src_mac are defined */
706 if( !r->src_ip && !r->src_mac )
707 {
708 b = fwd_ipt_init("nat");
709 fwd_ipt_add_format(b, " -A redirects -i ! %s -d %s",
710 n->ifname, inet_ntoa(r->dest_ip->addr));
711 fwd_ipt_add_proto(b, r->proto);
712 fwd_ipt_add_srcport(b, r->src_port);
713 fwd_ipt_add_destport(b, r->src_dport);
714 fwd_ipt_add_format(b, " -j MASQUERADE");
715 fwd_ipt_add_comment(b, "redir", z, n, NULL);
716 fwd_ipt_exec(b);
717 }
718 }
719
720 /* Build rules */
721 for( e = z->rules; e && (c = &e->section.rule); e = e->next )
722 {
723 /* Has destination, add forward rule for each network in target zone */
724 if( c->dest )
725 {
726 for( n2 = c->dest->networks; n2; n2 = n2->next )
727 {
728 printf("\n# Net %s (%s) - rule+dest"
729 " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n",
730 n->name, n->ifname, z->name, n->name, n->ifname,
731 f->dest->name, n2->name, n2->ifname);
732
733 b = fwd_ipt_init("filter");
734 fwd_ipt_add_format(b, " -A rules -i %s -o %s",
735 n->ifname, n2->ifname);
736 fwd_ipt_add_proto(b, c->proto);
737 fwd_ipt_add_icmptype(b, c->icmp_type);
738 fwd_ipt_add_srcmac(b, c->src_mac);
739 fwd_ipt_add_srcaddr(b, c->src_ip);
740 fwd_ipt_add_srcport(b, c->src_port);
741 fwd_ipt_add_destaddr(b, c->dest_ip);
742 fwd_ipt_add_destport(b, c->dest_port);
743 fwd_ipt_add_policy_target(b, c->target);
744 fwd_ipt_add_comment(b, "rule", z, n, n2);
745 fwd_ipt_exec(b);
746 }
747 }
748
749 /* No destination specified, treat it as input rule */
750 else
751 {
752 printf("\n# Net %s (%s) - rule Z:%s N:%s I:%s\n",
753 n->name, n->ifname, z->name, n->name, n->ifname);
754
755 b = fwd_ipt_init("filter");
756 fwd_ipt_add_format(b, " -A rules -i %s", n->ifname);
757 fwd_ipt_add_proto(b, c->proto);
758 fwd_ipt_add_icmptype(b, c->icmp_type);
759 fwd_ipt_add_srcmac(b, c->src_mac);
760 fwd_ipt_add_srcaddr(b, c->src_ip);
761 fwd_ipt_add_srcport(b, c->src_port);
762 fwd_ipt_add_destaddr(b, c->dest_ip);
763 fwd_ipt_add_destport(b, c->dest_port);
764 fwd_ipt_add_policy_target(b, c->target);
765 fwd_ipt_add_comment(b, "rule", z, n, n2);
766 fwd_ipt_exec(b);
767 }
768 }
769 }
770