contrib/fwd: implement fwd_ipt_delif() and fwd_ipt_clear_ruleset()
[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
26 /* -P <chain> <policy> */
27 static void fwd_r_set_policy(
28 struct iptc_handle *h, const char *chain, const char *policy
29 ) {
30 iptc_set_policy(chain, policy, NULL, h);
31 }
32
33 /* -N <chain> */
34 static void fwd_r_new_chain(struct iptc_handle *h, const char *chain)
35 {
36 iptc_create_chain(chain, h);
37 }
38
39 /* -A <chain1> -j <chain2> */
40 static void fwd_r_jump_chain(
41 struct iptc_handle *h, const char *chain1, const char *chain2
42 ) {
43 struct fwd_xt_rule *r;
44
45 if( (r = fwd_xt_init_rule(h)) != NULL )
46 {
47 fwd_xt_get_target(r, chain2);
48 fwd_xt_exec_rule(r, chain1);
49 }
50 }
51
52 /* -A <chain> -m state --state INVALID -j DROP */
53 static void fwd_r_drop_invalid(struct iptc_handle *h, const char *chain)
54 {
55 struct fwd_xt_rule *r;
56 struct xtables_match *m;
57
58 if( (r = fwd_xt_init_rule(h)) != NULL )
59 {
60 if( (m = fwd_xt_get_match(r, "state")) != NULL )
61 {
62 fwd_xt_parse_match(r, m, "--state", "INVALID");
63 fwd_xt_get_target(r, "DROP");
64 fwd_xt_exec_rule(r, chain);
65 }
66 }
67 }
68
69 /* -A <chain> -m state --state RELATED,ESTABLISHED -j ACCEPT */
70 static void fwd_r_accept_related(struct iptc_handle *h, const char *chain)
71 {
72 struct fwd_xt_rule *r;
73 struct xtables_match *m;
74
75 if( (r = fwd_xt_init_rule(h)) != NULL )
76 {
77 if( (m = fwd_xt_get_match(r, "state")) != NULL )
78 {
79 fwd_xt_parse_match(r, m, "--state", "RELATED,ESTABLISHED");
80 fwd_xt_get_target(r, "ACCEPT");
81 fwd_xt_exec_rule(r, chain);
82 }
83 }
84 }
85
86 /* -A INPUT -i lo -j ACCEPT; -A OUTPUT -o lo -j ACCEPT */
87 static void fwd_r_accept_lo(struct iptc_handle *h)
88 {
89 struct fwd_network_list n;
90 struct fwd_xt_rule *r;
91
92 n.ifname = "lo";
93
94 if( (r = fwd_xt_init_rule(h)) != NULL )
95 {
96 fwd_xt_parse_in(r, &n, 0);
97 fwd_xt_get_target(r, "ACCEPT");
98 fwd_xt_exec_rule(r, "INPUT");
99 }
100
101 if( (r = fwd_xt_init_rule(h)) != NULL )
102 {
103 fwd_xt_parse_out(r, &n, 0);
104 fwd_xt_get_target(r, "ACCEPT");
105 fwd_xt_exec_rule(r, "OUTPUT");
106 }
107 }
108
109 /* build syn_flood chain and jump rule */
110 static void fwd_r_add_synflood(struct iptc_handle *h, struct fwd_defaults *def)
111 {
112 struct fwd_proto p;
113 struct fwd_xt_rule *r;
114 struct xtables_match *m;
115 char buf[32];
116
117 /* -N syn_flood */
118 fwd_r_new_chain(h, "syn_flood");
119
120 /* return rule */
121 if( (r = fwd_xt_init_rule(h)) != NULL )
122 {
123 /* -p tcp */
124 p.type = FWD_PR_TCP;
125 fwd_xt_parse_proto(r, &p, 0);
126
127 /* -m tcp --syn */
128 if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
129 {
130 fwd_xt_parse_match(r, m, "--syn");
131 }
132
133 /* -m limit --limit x/second --limit-burst y */
134 if( (m = fwd_xt_get_match(r, "limit")) != NULL )
135 {
136 sprintf(buf, "%i/second", def->syn_rate);
137 fwd_xt_parse_match(r, m, "--limit", buf);
138
139 sprintf(buf, "%i", def->syn_burst);
140 fwd_xt_parse_match(r, m, "--limit-burst", buf);
141 }
142
143 /* -j RETURN; -A syn_flood */
144 fwd_xt_get_target(r, "RETURN");
145 fwd_xt_exec_rule(r, "syn_flood");
146 }
147
148 /* drop rule */
149 if( (r = fwd_xt_init_rule(h)) != NULL )
150 {
151 /* -j DROP; -A syn_flood */
152 fwd_xt_get_target(r, "DROP");
153 fwd_xt_exec_rule(r, "syn_flood");
154 }
155
156 /* jump to syn_flood rule */
157 if( (r = fwd_xt_init_rule(h)) != NULL )
158 {
159 /* -p tcp */
160 p.type = FWD_PR_TCP;
161 fwd_xt_parse_proto(r, &p, 0);
162
163 /* -m tcp --syn */
164 if( (m = fwd_xt_get_match(r, "tcp")) != NULL )
165 {
166 fwd_xt_parse_match(r, m, "--syn");
167 }
168
169 /* -j syn_flood; -A INPUT */
170 fwd_xt_get_target(r, "syn_flood");
171 fwd_xt_exec_rule(r, "INPUT");
172 }
173 }
174
175 /* build reject target chain */
176 static void fwd_r_handle_reject(struct iptc_handle *h)
177 {
178 struct fwd_proto p;
179 struct fwd_xt_rule *r;
180 struct xtables_target *t;
181
182 /* -N handle_reject */
183 fwd_r_new_chain(h, "handle_reject");
184
185 /* tcp reject rule */
186 if( (r = fwd_xt_init_rule(h)) != NULL )
187 {
188 /* -p tcp */
189 p.type = FWD_PR_TCP;
190 fwd_xt_parse_proto(r, &p, 0);
191
192 /* -j REJECT --reject-with tcp-reset */
193 if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
194 {
195 fwd_xt_parse_target(r, t, "--reject-with", "tcp-reset");
196 }
197
198 /* -A handle_reject */
199 fwd_xt_exec_rule(r, "handle_reject");
200 }
201
202 /* common reject rule */
203 if( (r = fwd_xt_init_rule(h)) != NULL )
204 {
205 /* -j REJECT --reject-with icmp-port-unreachable */
206 if( (t = fwd_xt_get_target(r, "REJECT")) != NULL )
207 {
208 fwd_xt_parse_target(r, t, "--reject-with",
209 "icmp-port-unreachable");
210 }
211
212 /* -A handle_reject */
213 fwd_xt_exec_rule(r, "handle_reject");
214 }
215 }
216
217 /* build drop target chain */
218 static void fwd_r_handle_drop(struct iptc_handle *h)
219 {
220 struct fwd_xt_rule *r;
221
222 /* -N handle_drop */
223 fwd_r_new_chain(h, "handle_drop");
224
225 /* common drop rule */
226 if( (r = fwd_xt_init_rule(h)) != NULL )
227 {
228 /* -j DROP; -A handle_reject */
229 fwd_xt_get_target(r, "DROP");
230 fwd_xt_exec_rule(r, "handle_reject");
231 }
232 }
233
234 /* build accept target chain */
235 static void fwd_r_handle_accept(struct iptc_handle *h)
236 {
237 struct fwd_xt_rule *r;
238
239 /* -N handle_accept */
240 fwd_r_new_chain(h, "handle_accept");
241
242 /* common accept rule */
243 if( (r = fwd_xt_init_rule(h)) != NULL )
244 {
245 /* -j ACCEPT; -A handle_accept */
246 fwd_xt_get_target(r, "ACCEPT");
247 fwd_xt_exec_rule(r, "handle_accept");
248 }
249 }
250
251 /* add comment match */
252 static void fwd_r_add_comment(
253 struct fwd_xt_rule *r, const char *t, struct fwd_zone *z,
254 struct fwd_network_list *n, struct fwd_network_list *n2
255 ) {
256 struct xtables_match *m;
257 char buf[256];
258
259 if( (m = fwd_xt_get_match(r, "comment")) != NULL )
260 {
261 if( (n != NULL) && (n2 != NULL) )
262 snprintf(buf, sizeof(buf), "%s:%s src:%s dest:%s",
263 t, z->name, n->name, n2->name);
264 else if( (n == NULL) && (n2 != NULL) )
265 snprintf(buf, sizeof(buf), "%s:%s dest:%s", t, z->name, n2->name);
266 else
267 snprintf(buf, sizeof(buf), "%s:%s src:%s", t, z->name, n->name);
268
269 fwd_xt_parse_match(r, m, "--comment", buf);
270 }
271 }
272
273 /* add --sport (if applicable) */
274 static void fwd_r_add_sport(
275 struct fwd_xt_rule *r, struct fwd_portrange *p
276 ) {
277 int proto = r->entry->ip.proto;
278 char buf[12];
279 struct xtables_match *m;
280
281 /* have portrange and proto is tcp or udp ... */
282 if( (p != NULL) && ((proto == 6) || (proto == 17)) )
283 {
284 /* get match ... */
285 if( (m = fwd_xt_get_match(r, (proto == 6) ? "tcp" : "udp")) != NULL )
286 {
287 snprintf(buf, sizeof(buf), "%u:%u", p->min, p->max);
288 fwd_xt_parse_match(r, m, "--sport", buf);
289 }
290 }
291 }
292
293 /* add --dport (if applicable) */
294 static void fwd_r_add_dport(
295 struct fwd_xt_rule *r, struct fwd_portrange *p
296 ) {
297 int proto = r->entry->ip.proto;
298 char buf[12];
299 struct xtables_match *m;
300
301 /* have portrange and proto is tcp or udp ... */
302 if( (p != NULL) && ((proto == 6) || (proto == 17)) )
303 {
304 /* get match ... */
305 if( (m = fwd_xt_get_match(r, (proto == 6) ? "tcp" : "udp")) != NULL )
306 {
307 snprintf(buf, sizeof(buf), "%u:%u", p->min, p->max);
308 fwd_xt_parse_match(r, m, "--dport", buf);
309 }
310 }
311 }
312
313 /* add --icmp-type (of applicable) */
314 static void fwd_r_add_icmptype(
315 struct fwd_xt_rule *r, struct fwd_icmptype *i
316 ) {
317 int proto = r->entry->ip.proto;
318 struct xtables_match *m;
319 char buf[32];
320
321 /* have icmp-type and proto is icmp ... */
322 if( (i != NULL) && (proto == 1) )
323 {
324 /* get match ... */
325 if( (m = fwd_xt_get_match(r, "icmp")) != NULL )
326 {
327 if( i->name[0] )
328 snprintf(buf, sizeof(buf), "%s", i->name);
329 else
330 snprintf(buf, sizeof(buf), "%u/%u", i->type, i->code);
331
332 fwd_xt_parse_match(r, m, "--icmp-type", buf);
333 }
334 }
335 }
336
337 /* add -m mac --mac-source ... */
338 static void fwd_r_add_srcmac(
339 struct fwd_xt_rule *r, struct fwd_mac *mac
340 ) {
341 struct xtables_match *m;
342 char buf[18];
343
344 if( mac != NULL )
345 {
346 if( (m = fwd_xt_get_match(r, "mac")) != NULL )
347 {
348 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
349 mac->mac[0], mac->mac[1], mac->mac[2],
350 mac->mac[3], mac->mac[4], mac->mac[5]);
351
352 fwd_xt_parse_match(r, m, "--mac-source", buf);
353 }
354 }
355 }
356
357 /* add policy target */
358 static void fwd_r_add_policytarget(
359 struct fwd_xt_rule *r, enum fwd_policy pol
360 ) {
361 switch(pol)
362 {
363 case FWD_P_ACCEPT:
364 fwd_xt_get_target(r, "handle_accept");
365 break;
366
367 case FWD_P_REJECT:
368 fwd_xt_get_target(r, "handle_reject");
369 break;
370
371 case FWD_P_DROP:
372 case FWD_P_UNSPEC:
373 fwd_xt_get_target(r, "handle_drop");
374 break;
375 }
376 }
377
378 /* add dnat target */
379 static void fwd_r_add_dnattarget(
380 struct fwd_xt_rule *r, struct fwd_cidr *c, struct fwd_portrange *p
381 ) {
382 struct xtables_target *t;
383 char buf[32];
384
385 if( c != NULL )
386 {
387 if( (t = fwd_xt_get_target(r, "DNAT")) != NULL )
388 {
389 if( p != NULL )
390 snprintf(buf, sizeof(buf), "%s:%u-%u",
391 inet_ntoa(c->addr), p->min, p->max);
392 else
393 snprintf(buf, sizeof(buf), "%s", inet_ntoa(c->addr));
394
395 fwd_xt_parse_target(r, t, "--to-destination", buf);
396 }
397 }
398 }
399
400 /* parse comment string and look for match */
401 static int fwd_r_cmp(const char *what, const char *cmt, const char *cmp)
402 {
403 char *match;
404
405 printf("CMP: %s %s %s\n", what, cmt, cmp);
406
407 if( (match = strstr(cmt, what)) == NULL )
408 return 0;
409
410 match += strlen(what);
411
412 if( strncmp(match, cmp, strlen(cmp)) != 0 )
413 return 0;
414
415 if( (match[strlen(cmp)] != ' ') && (match[strlen(cmp)] != '\0') )
416 return 0;
417
418 return 1;
419 }
420
421
422 static void fwd_ipt_defaults_create(struct fwd_data *d)
423 {
424 struct fwd_defaults *def = &d->section.defaults;
425 struct iptc_handle *h_filter, *h_nat;
426
427 if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
428 fwd_fatal("Unable to obtain libiptc handle");
429
430 /* policies */
431 fwd_r_set_policy(h_filter, "INPUT",
432 def->input == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
433 fwd_r_set_policy(h_filter, "OUTPUT",
434 def->output == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
435 fwd_r_set_policy(h_filter, "FORWARD",
436 def->forward == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
437
438 /* invalid state drop */
439 if( def->drop_invalid )
440 {
441 fwd_r_drop_invalid(h_filter, "INPUT");
442 fwd_r_drop_invalid(h_filter, "OUTPUT");
443 fwd_r_drop_invalid(h_filter, "FORWARD");
444 }
445
446 /* default accept related */
447 fwd_r_accept_related(h_filter, "INPUT");
448 fwd_r_accept_related(h_filter, "OUTPUT");
449 fwd_r_accept_related(h_filter, "FORWARD");
450
451 /* default accept on lo */
452 fwd_r_accept_lo(h_filter);
453
454 /* syn flood protection */
455 if( def->syn_flood )
456 {
457 fwd_r_add_synflood(h_filter, def);
458 }
459
460 /* rule container chains */
461 fwd_r_new_chain(h_filter, "mssfix");
462 fwd_r_new_chain(h_filter, "zones");
463 fwd_r_new_chain(h_filter, "rules");
464 fwd_r_new_chain(h_filter, "redirects");
465 fwd_r_new_chain(h_filter, "forwardings");
466 fwd_r_jump_chain(h_filter, "INPUT", "rules");
467 fwd_r_jump_chain(h_filter, "FORWARD", "mssfix");
468 fwd_r_jump_chain(h_filter, "FORWARD", "zones");
469 fwd_r_jump_chain(h_filter, "FORWARD", "rules");
470 fwd_r_jump_chain(h_filter, "FORWARD", "redirects");
471 fwd_r_jump_chain(h_filter, "FORWARD", "forwardings");
472 fwd_r_new_chain(h_nat, "zonemasq");
473 fwd_r_new_chain(h_nat, "redirects");
474 fwd_r_new_chain(h_nat, "loopback");
475 fwd_r_jump_chain(h_nat, "POSTROUTING", "zonemasq");
476 fwd_r_jump_chain(h_nat, "PREROUTING", "redirects");
477 fwd_r_jump_chain(h_nat, "POSTROUTING", "loopback");
478
479 /* standard drop, accept, reject chain */
480 fwd_r_handle_drop(h_filter);
481 fwd_r_handle_accept(h_filter);
482 fwd_r_handle_reject(h_filter);
483
484
485 if( !iptc_commit(h_nat) )
486 fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
487
488 if( !iptc_commit(h_filter) )
489 fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
490
491 iptc_free(h_nat);
492 iptc_free(h_filter);
493 }
494
495
496 void fwd_ipt_build_ruleset(struct fwd_handle *h)
497 {
498 struct fwd_data *e;
499
500 fwd_xt_init();
501
502 for( e = h->conf; e; e = e->next )
503 {
504 switch(e->type)
505 {
506 case FWD_S_DEFAULTS:
507 printf("\n## DEFAULTS\n");
508 fwd_ipt_defaults_create(e);
509 break;
510
511 case FWD_S_INCLUDE:
512 printf("\n## INCLUDE %s\n", e->section.include.path);
513 break;
514
515 case FWD_S_ZONE:
516 case FWD_S_FORWARD:
517 case FWD_S_REDIRECT:
518 case FWD_S_RULE:
519 /* Make gcc happy */
520 break;
521 }
522 }
523 }
524
525
526 static struct fwd_zone *
527 fwd_lookup_zone(struct fwd_handle *h, const char *net)
528 {
529 struct fwd_data *e;
530 struct fwd_network_list *n;
531
532 for( e = h->conf; e; e = e->next )
533 if( e->type == FWD_S_ZONE )
534 for( n = e->section.zone.networks; n; n = n->next )
535 if( !strcmp(n->name, net) )
536 return &e->section.zone;
537
538 return NULL;
539 }
540
541 static struct fwd_network_list *
542 fwd_lookup_network(struct fwd_zone *z, const char *net)
543 {
544 struct fwd_network_list *n;
545
546 for( n = z->networks; n; n = n->next )
547 if( !strcmp(n->name, net) )
548 return n;
549
550 return NULL;
551 }
552
553 static struct fwd_addr_list *
554 fwd_lookup_addr(struct fwd_handle *h, struct fwd_network_list *n)
555 {
556 struct fwd_addr_list *a;
557
558 if( n != NULL )
559 for( a = h->addrs; a; a = a->next )
560 if( !strcmp(a->ifname, n->ifname) )
561 return a;
562
563 return NULL;
564 }
565
566 void fwd_ipt_addif(struct fwd_handle *h, const char *net)
567 {
568 struct fwd_data *e;
569 struct fwd_zone *z;
570 struct fwd_rule *c;
571 struct fwd_redirect *r;
572 struct fwd_forwarding *f;
573 struct fwd_addr_list *a, *a2;
574 struct fwd_network_list *n, *n2;
575 struct fwd_proto p;
576
577 struct fwd_xt_rule *x;
578 struct xtables_match *m;
579 struct xtables_target *t;
580
581 struct iptc_handle *h_filter, *h_nat;
582
583 if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
584 fwd_fatal("Unable to obtain libiptc handle");
585
586
587 if( !(z = fwd_lookup_zone(h, net)) )
588 return;
589
590 if( !(n = fwd_lookup_network(z, net)) )
591 return;
592
593 if( !(a = fwd_lookup_addr(h, n)) )
594 return;
595
596 printf("\n\n#\n# addif(%s)\n#\n", net);
597
598 /* Build masquerading rule */
599 if( z->masq )
600 {
601 printf("\n# Net %s (%s) - masq\n", n->name, n->ifname);
602
603 if( (x = fwd_xt_init_rule(h_nat)) != NULL )
604 {
605 fwd_xt_parse_out(x, n, 0); /* -o ... */
606 fwd_xt_get_target(x, "MASQUERADE"); /* -j MASQUERADE */
607 fwd_r_add_comment(x, "masq", z, NULL, n); /* -m comment ... */
608 fwd_xt_exec_rule(x, "zonemasq"); /* -A zonemasq */
609 }
610 }
611
612 /* Build MSS fix rule */
613 if( z->mtu_fix )
614 {
615 printf("\n# Net %s (%s) - mtu_fix\n", n->name, n->ifname);
616
617 if( (x = fwd_xt_init_rule(h_filter)) != NULL )
618 {
619 p.type = FWD_PR_TCP;
620 fwd_xt_parse_out(x, n, 0); /* -o ... */
621 fwd_xt_parse_proto(x, &p, 0); /* -p tcp */
622
623 /* -m tcp --tcp-flags SYN,RST SYN */
624 if( (m = fwd_xt_get_match(x, "tcp")) != NULL )
625 fwd_xt_parse_match(x, m, "--tcp-flags", "SYN,RST", "SYN");
626
627 /* -j TCPMSS --clamp-mss-to-pmtu */
628 if( (t = fwd_xt_get_target(x, "TCPMSS")) != NULL )
629 fwd_xt_parse_target(x, t, "--clamp-mss-to-pmtu");
630
631 /* -m comment ... */
632 fwd_r_add_comment(x, "mssfix", z, NULL, n);
633
634 /* -A mssfix */
635 fwd_xt_exec_rule(x, "mssfix");
636 }
637 }
638
639 /* Build intra-zone forwarding rules */
640 for( n2 = z->networks; n2; n2 = n2->next )
641 {
642 if( (a2 = fwd_lookup_addr(h, n2)) != NULL )
643 {
644 printf("\n# Net %s (%s) - intra-zone-forwarding"
645 " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n",
646 n->name, n->ifname, z->name, n->name, n->ifname,
647 z->name, n2->name, n2->ifname);
648
649 if( (x = fwd_xt_init_rule(h_filter)) != NULL )
650 {
651 fwd_xt_parse_in(x, n, 0); /* -i ... */
652 fwd_xt_parse_out(x, n2, 0); /* -o ... */
653 fwd_r_add_policytarget(x, z->forward); /* -j handle_... */
654 fwd_r_add_comment(x, "zone", z, n, n2); /* -m comment ... */
655 fwd_xt_exec_rule(x, "zones"); /* -A zones */
656 }
657 }
658 }
659
660 /* Build inter-zone forwarding rules */
661 for( e = z->forwardings; e && (f = &e->section.forwarding); e = e->next )
662 {
663 for( n2 = f->dest->networks; n2; n2 = n2->next )
664 {
665 printf("\n# Net %s (%s) - inter-zone-forwarding"
666 " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n",
667 n->name, n->ifname, z->name, n->name, n->ifname,
668 f->dest->name, n2->name, n2->ifname);
669
670 /* Build forwarding rule */
671 if( (x = fwd_xt_init_rule(h_filter)) != NULL )
672 {
673 fwd_xt_parse_in(x, n, 0); /* -i ... */
674 fwd_xt_parse_out(x, n2, 0); /* -o ... */
675 fwd_r_add_policytarget(x, FWD_P_ACCEPT); /* -j handle_... */
676 fwd_r_add_comment(x, "forward", z, n, n2); /* -m comment ... */
677 fwd_xt_exec_rule(x, "forwardings"); /* -A forwardings */
678 }
679 }
680 }
681
682 /* Build DNAT rules */
683 for( e = z->redirects; e && (r = &e->section.redirect); e = e->next )
684 {
685 printf("\n# Net %s (%s) - redirect Z:%s N:%s I:%s\n",
686 n->name, n->ifname, z->name, n->name, n->ifname);
687
688 /* DNAT */
689 if( (x = fwd_xt_init_rule(h_nat)) != NULL )
690 {
691 fwd_xt_parse_in(x, n, 0); /* -i ... */
692 fwd_xt_parse_src(x, r->src_ip, 0); /* -s ... */
693 fwd_xt_parse_dest(x, &a->ipaddr, 0); /* -d ... */
694 fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */
695 fwd_r_add_sport(x, r->src_port); /* --sport ... */
696 fwd_r_add_dport(x, r->src_dport); /* --dport ... */
697 fwd_r_add_srcmac(x, r->src_mac); /* -m mac --mac-source ... */
698 fwd_r_add_dnattarget(x, r->dest_ip, r->dest_port); /* -j DNAT ... */
699 fwd_r_add_comment(x, "redir", z, n, NULL); /* -m comment ... */
700 fwd_xt_exec_rule(x, "redirects"); /* -A redirects */
701 }
702
703 /* Forward */
704 if( (x = fwd_xt_init_rule(h_filter)) != NULL )
705 {
706 fwd_xt_parse_in(x, n, 0); /* -i ... */
707 fwd_xt_parse_src(x, r->src_ip, 0); /* -s ... */
708 fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */
709 fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */
710 fwd_r_add_srcmac(x, r->src_mac); /* -m mac --mac-source ... */
711 fwd_r_add_sport(x, r->src_port); /* --sport ... */
712 fwd_r_add_dport(x, r->dest_port); /* --dport ... */
713 fwd_r_add_policytarget(x, FWD_P_ACCEPT); /* -j handle_accept */
714 fwd_r_add_comment(x, "redir", z, n, NULL); /* -m comment ... */
715 fwd_xt_exec_rule(x, "redirects"); /* -A redirects */
716 }
717
718 /* Add loopback rule if neither src_ip nor src_mac are defined */
719 if( !r->src_ip && !r->src_mac )
720 {
721 if( (x = fwd_xt_init_rule(h_nat)) != NULL )
722 {
723 fwd_xt_parse_in(x, n, 1); /* -i ! ... */
724 fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */
725 fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */
726 fwd_r_add_sport(x, r->src_port); /* --sport ... */
727 fwd_r_add_dport(x, r->src_dport); /* --dport ... */
728 fwd_xt_get_target(x, "MASQUERADE"); /* -j MASQUERADE */
729 fwd_r_add_comment(x, "redir", z, n, NULL); /* -m comment ... */
730 fwd_xt_exec_rule(x, "loopback"); /* -A loopback */
731 }
732 }
733 }
734
735 /* Build rules */
736 for( e = z->rules; e && (c = &e->section.rule); e = e->next )
737 {
738 /* Has destination, add forward rule for each network in target zone */
739 if( c->dest )
740 {
741 for( n2 = c->dest->networks; n2; n2 = n2->next )
742 {
743 printf("\n# Net %s (%s) - rule+dest"
744 " Z:%s N:%s I:%s -> Z:%s N:%s I:%s\n",
745 n->name, n->ifname, z->name, n->name, n->ifname,
746 f->dest->name, n2->name, n2->ifname);
747
748 if( (x = fwd_xt_init_rule(h_filter)) != NULL )
749 {
750 fwd_xt_parse_in(x, n, 0); /* -i ... */
751 fwd_xt_parse_out(x, n2, 0); /* -o ... */
752 fwd_xt_parse_src(x, c->src_ip, 0); /* -s ... */
753 fwd_xt_parse_dest(x, c->dest_ip, 0); /* -d ... */
754 fwd_xt_parse_proto(x, c->proto, 0); /* -p ... */
755 fwd_r_add_icmptype(x, c->icmp_type); /* --icmp-type ... */
756 fwd_r_add_srcmac(x, c->src_mac); /* --mac-source ... */
757 fwd_r_add_sport(x, c->src_port); /* --sport ... */
758 fwd_r_add_dport(x, c->dest_port); /* --dport ... */
759 fwd_r_add_policytarget(x, c->target); /* -j handle_... */
760 fwd_r_add_comment(x, "rule", z, n, n2); /* -m comment ... */
761 fwd_xt_exec_rule(x, "rules"); /* -A rules */
762 }
763 }
764 }
765
766 /* No destination specified, treat it as input rule */
767 else
768 {
769 printf("\n# Net %s (%s) - rule Z:%s N:%s I:%s\n",
770 n->name, n->ifname, z->name, n->name, n->ifname);
771
772 if( (x = fwd_xt_init_rule(h_filter)) != NULL )
773 {
774 fwd_xt_parse_in(x, n, 0); /* -i ... */
775 fwd_xt_parse_src(x, c->src_ip, 0); /* -s ... */
776 fwd_xt_parse_dest(x, c->dest_ip, 0); /* -d ... */
777 fwd_xt_parse_proto(x, c->proto, 0); /* -p ... */
778 fwd_r_add_icmptype(x, c->icmp_type); /* --icmp-type ... */
779 fwd_r_add_srcmac(x, c->src_mac); /* --mac-source ... */
780 fwd_r_add_sport(x, c->src_port); /* --sport ... */
781 fwd_r_add_dport(x, c->dest_port); /* --dport ... */
782 fwd_r_add_policytarget(x, c->target); /* -j handle_... */
783 fwd_r_add_comment(x, "rule", z, n, NULL); /* -m comment ... */
784 fwd_xt_exec_rule(x, "rules"); /* -A rules */
785 }
786 }
787 }
788
789 if( !iptc_commit(h_nat) )
790 fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
791
792 if( !iptc_commit(h_filter) )
793 fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
794
795 iptc_free(h_nat);
796 iptc_free(h_filter);
797 }
798
799
800 static void fwd_ipt_delif_table(struct iptc_handle *h, const char *net)
801 {
802 struct xt_entry_match *m;
803 struct ipt_entry *e;
804 const char *chain, *comment;
805 size_t off = 0, num = 0;
806
807 /* iterate chains */
808 for( chain = iptc_first_chain(h); chain;
809 chain = iptc_next_chain(h)
810 ) {
811 /* iterate rules */
812 for( e = iptc_first_rule(chain, h), num = 0; e;
813 e = iptc_next_rule(e, h), num++
814 ) {
815 repeat_rule:
816
817 /* skip entries w/o matches */
818 if( ! e->target_offset )
819 continue;
820
821 /* iterate matches */
822 for( off = sizeof(struct ipt_entry);
823 off < e->target_offset;
824 off += m->u.match_size
825 ) {
826 m = (void *)e + off;
827
828 /* yay */
829 if( ! strcmp(m->u.user.name, "comment") )
830 {
831 /* better use struct_xt_comment_info but well... */
832 comment = (void *)m + sizeof(struct xt_entry_match);
833
834 if( fwd_r_cmp("src:", comment, net) )
835 {
836 e = iptc_next_rule(e, h);
837 iptc_delete_num_entry(chain, num, h);
838
839 if( e != NULL )
840 goto repeat_rule;
841 else
842 break;
843 }
844 }
845 }
846 }
847 }
848 }
849
850 void fwd_ipt_delif(struct fwd_handle *h, const char *net)
851 {
852 struct iptc_handle *h_filter, *h_nat;
853
854 if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
855 fwd_fatal("Unable to obtain libiptc handle");
856
857
858 printf("\n\n#\n# delif(%s)\n#\n", net);
859
860 /* delete network related rules */
861 fwd_ipt_delif_table(h_nat, net);
862 fwd_ipt_delif_table(h_filter, net);
863
864
865 if( !iptc_commit(h_nat) )
866 fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
867
868 if( !iptc_commit(h_filter) )
869 fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
870
871 iptc_free(h_nat);
872 iptc_free(h_filter);
873 }
874
875
876 static void fwd_ipt_clear_ruleset_table(struct iptc_handle *h)
877 {
878 const char *chain;
879
880 /* pass 1: flush all chains */
881 for( chain = iptc_first_chain(h); chain;
882 chain = iptc_next_chain(h)
883 ) {
884 iptc_flush_entries(chain, h);
885 }
886
887 /* pass 2: remove user defined chains */
888 for( chain = iptc_first_chain(h); chain;
889 chain = iptc_next_chain(h)
890 ) {
891 if( ! iptc_builtin(chain, h) )
892 iptc_delete_chain(chain, h);
893 }
894 }
895
896 void fwd_ipt_clear_ruleset(struct fwd_handle *h)
897 {
898 struct iptc_handle *h_filter, *h_nat;
899
900 if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) )
901 fwd_fatal("Unable to obtain libiptc handle");
902
903 /* flush tables */
904 fwd_ipt_clear_ruleset_table(h_nat);
905 fwd_ipt_clear_ruleset_table(h_filter);
906
907 /* revert policies */
908 fwd_r_set_policy(h_filter, "INPUT", "ACCEPT");
909 fwd_r_set_policy(h_filter, "OUTPUT", "ACCEPT");
910 fwd_r_set_policy(h_filter, "FORWARD", "ACCEPT");
911
912
913 if( !iptc_commit(h_nat) )
914 fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno));
915
916 if( !iptc_commit(h_filter) )
917 fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno));
918
919 iptc_free(h_nat);
920 iptc_free(h_filter);
921 }
922