2 * fwd - OpenWrt firewall daemon - iptables rule set
4 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
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.
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.
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/.
22 #include "fwd_rules.h"
25 fwd_ipt_rule_append(struct fwd_ipt_rulebuf *r, const char *fmt, ...)
28 char buf[256]; buf[0] = 0;
32 len = vsnprintf(buf, sizeof(buf), fmt, ap);
37 r->buf = realloc(r->buf, r->len + len + 1);
38 memcpy(&r->buf[r->len], buf, len);
39 r->buf[r->len + len] = 0;
44 static struct fwd_ipt_rulebuf * fwd_ipt_init(const char *table)
46 struct fwd_ipt_rulebuf *r;
48 if( (r = fwd_alloc_ptr(struct fwd_ipt_rulebuf)) != NULL )
50 fwd_ipt_rule_append(r, IPT " -t %s", table);
57 static void fwd_ipt_add_srcport(
58 struct fwd_ipt_rulebuf *r, struct fwd_portrange *p
63 fwd_ipt_rule_append(r, " --sport %u:%u", p->min, p->max);
65 fwd_ipt_rule_append(r, " --sport %u", p->min);
69 static void fwd_ipt_add_destport(
70 struct fwd_ipt_rulebuf *r, struct fwd_portrange *p
75 fwd_ipt_rule_append(r, " --dport %u:%u", p->min, p->max);
77 fwd_ipt_rule_append(r, " --dport %u", p->min);
81 static void fwd_ipt_add_proto(
82 struct fwd_ipt_rulebuf *r, struct fwd_proto *p
89 fwd_ipt_rule_append(r, " -p tcp -p udp");
93 fwd_ipt_rule_append(r, " -p tcp");
97 fwd_ipt_rule_append(r, " -p udp");
101 fwd_ipt_rule_append(r, " -p icmp");
105 fwd_ipt_rule_append(r, " -p all");
109 fwd_ipt_rule_append(r, " -p %u", p->proto);
115 static void fwd_ipt_add_srcaddr(
116 struct fwd_ipt_rulebuf *r, struct fwd_cidr *c
121 fwd_ipt_rule_append(r, " -s %s/%u",
122 inet_ntoa(c->addr), c->prefix);
124 fwd_ipt_rule_append(r, " -s %s", inet_ntoa(c->addr));
128 static void fwd_ipt_add_destaddr(
129 struct fwd_ipt_rulebuf *r, struct fwd_cidr *c
134 fwd_ipt_rule_append(r, " -d %s/%u",
135 inet_ntoa(c->addr), c->prefix);
137 fwd_ipt_rule_append(r, " -d %s", inet_ntoa(c->addr));
141 static void fwd_ipt_add_srcmac(
142 struct fwd_ipt_rulebuf *r, struct fwd_mac *m
146 fwd_ipt_rule_append(r,
147 " -m mac --mac-source %02x:%02x:%02x:%02x:%02x:%02x",
148 m->mac[0], m->mac[1], m->mac[2],
149 m->mac[3], m->mac[4], m->mac[5]);
153 static void fwd_ipt_add_icmptype(
154 struct fwd_ipt_rulebuf *r, struct fwd_icmptype *i
159 fwd_ipt_rule_append(r, " --icmp-type %s", i->name);
160 else if( i->code > -1 )
161 fwd_ipt_rule_append(r, " --icmp-type %u/%u", i->type, i->code);
163 fwd_ipt_rule_append(r, " --icmp-type %u", i->type);
167 static void fwd_ipt_add_dnat_target(
168 struct fwd_ipt_rulebuf *r, struct fwd_cidr *c, struct fwd_portrange *p
172 fwd_ipt_rule_append(r, " -j DNAT --to-destination %s",
175 if( (p != NULL) && (p->min < p->max) )
176 fwd_ipt_rule_append(r, ":%u-%u", p->min, p->max);
178 fwd_ipt_rule_append(r, ":%u", p->min);
182 static void fwd_ipt_exec(struct fwd_ipt_rulebuf *r)
185 printf("%s\n", r->buf);
187 fwd_free_ptr(r->buf);
191 static const char * fwd_str_policy(enum fwd_policy pol)
193 return (pol == FWD_P_ACCEPT ? "ACCEPT" : "DROP");
196 static const char * fwd_str_target(enum fwd_policy pol)
214 static void fwd_ipt_defaults_create(struct fwd_data *d)
216 struct fwd_defaults *def = &d->section.defaults;
219 fwd_ipt_exec_format("filter", " -P INPUT %s", fwd_str_policy(def->input));
220 fwd_ipt_exec_format("filter", " -P OUTPUT %s", fwd_str_policy(def->output));
221 fwd_ipt_exec_format("filter", " -P FORWARD %s", fwd_str_policy(def->forward));
223 /* invalid state drop */
224 if( def->drop_invalid )
226 fwd_ipt_exec_format("filter", " -A INPUT --state INVALID -j DROP");
227 fwd_ipt_exec_format("filter", " -A OUTPUT --state INVALID -j DROP");
228 fwd_ipt_exec_format("filter", " -A FORWARD --state INVALID -j DROP");
231 /* default accept related */
232 fwd_ipt_exec_format("filter", " -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT");
233 fwd_ipt_exec_format("filter", " -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT");
234 fwd_ipt_exec_format("filter", " -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT");
236 /* default accept on lo */
237 fwd_ipt_exec_format("filter", " -A INPUT -i lo -j ACCEPT");
238 fwd_ipt_exec_format("filter", " -A OUTPUT -o lo -j ACCEPT");
240 /* syn flood protection */
243 fwd_ipt_exec_format("filter", " -N syn_flood");
245 fwd_ipt_exec_format("filter",
246 " -A syn_flood -p tcp --syn -m limit --limit %i/second"
247 " --limit-burst %i -j RETURN",
248 def->syn_rate, def->syn_burst);
250 fwd_ipt_exec_format("filter", " -A syn_flood -j DROP");
251 fwd_ipt_exec_format("filter", " -A INPUT -p tcp --syn -j syn_flood");
254 /* standard input/output/forward chain */
255 fwd_ipt_exec_format("filter", " -N input");
256 fwd_ipt_exec_format("filter", " -N output");
257 fwd_ipt_exec_format("filter", " -N forward");
258 fwd_ipt_exec_format("filter", " -A INPUT -j input");
259 fwd_ipt_exec_format("filter", " -A OUTPUT -j output");
260 fwd_ipt_exec_format("filter", " -A FORWARD -j forward");
262 /* standard reject chain */
263 fwd_ipt_exec_format("filter", " -N reject");
264 fwd_ipt_exec_format("filter", " -A reject -p tcp -j REJECT --reject-with tcp-reset");
265 fwd_ipt_exec_format("filter", " -A reject -j REJECT --reject-with icmp-port-unreachable");
268 static void fwd_ipt_zone_create(struct fwd_data *d)
270 struct fwd_zone *z = &d->section.zone;
272 if( !strcmp(z->name, "loopback") )
275 fwd_ipt_exec_format("filter", " -N zone_%s", z->name);
276 fwd_ipt_exec_format("filter", " -N zone_%s_forward", z->name);
277 fwd_ipt_exec_format("filter", " -N zone_%s_ACCEPT", z->name);
278 fwd_ipt_exec_format("filter", " -N zone_%s_REJECT", z->name);
279 fwd_ipt_exec_format("filter", " -N zone_%s_DROP", z->name);
280 fwd_ipt_exec_format("filter", " -N zone_%s_MSSFIX", z->name);
282 if( z->forward != FWD_P_UNSPEC )
283 fwd_ipt_exec_format("filter", " -A zone_%s_forward -j zone_%s_%s",
284 z->name, z->name, fwd_str_target(z->forward));
286 if( z->input != FWD_P_UNSPEC )
287 fwd_ipt_exec_format("filter", " -A zone_%s -j zone_%s_%s",
288 z->name, z->name, fwd_str_target(z->input));
290 if( z->output != FWD_P_UNSPEC )
291 fwd_ipt_exec_format("filter", " -A output -j zone_%s_%s",
292 z->name, fwd_str_target(z->output));
294 fwd_ipt_exec_format("nat", " -N zone_%s_nat", z->name);
295 fwd_ipt_exec_format("nat", " -N zone_%s_prerouting", z->name);
296 fwd_ipt_exec_format("raw", " -N zone_%s_notrack", z->name);
299 fwd_ipt_exec_format("nat", " -A POSTROUTING -j zone_%s_nat",
303 fwd_ipt_exec_format("filter", " -A FORWARD -j zone_%s_MSSFIX",
307 static void fwd_ipt_forwarding_create(struct fwd_data *d)
309 struct fwd_forwarding *f = &d->section.forwarding;
310 struct fwd_ipt_rulebuf *b;
312 b = fwd_ipt_init("filter");
315 fwd_ipt_add_format(b, " -I zone_%s_forward 1", f->src->name);
317 fwd_ipt_add_format(b, " -I forward 1");
320 fwd_ipt_add_format(b, " -j zone_%s_ACCEPT", f->dest->name);
322 fwd_ipt_add_format(b, " -j ACCEPT");
327 static void fwd_ipt_redirect_create(struct fwd_data *d)
329 struct fwd_redirect *r = &d->section.redirect;
330 struct fwd_ipt_rulebuf *b;
332 b = fwd_ipt_init("nat");
333 fwd_ipt_add_format(b, " -A zone_%s_prerouting", r->src->name);
334 fwd_ipt_add_proto(b, r->proto);
335 fwd_ipt_add_srcaddr(b, r->src_ip);
336 fwd_ipt_add_srcport(b, r->src_port);
337 fwd_ipt_add_destport(b, r->src_dport);
338 fwd_ipt_add_srcmac(b, r->src_mac);
339 fwd_ipt_add_dnat_target(b, r->dest_ip, r->dest_port);
342 b = fwd_ipt_init("nat");
343 fwd_ipt_add_format(b, " -I zone_%s_forward 1", r->src->name);
344 fwd_ipt_add_proto(b, r->proto);
345 fwd_ipt_add_srcmac(b, r->src_mac);
346 fwd_ipt_add_srcaddr(b, r->src_ip);
347 fwd_ipt_add_srcport(b, r->src_port);
348 fwd_ipt_add_destaddr(b, r->dest_ip);
349 fwd_ipt_add_destport(b, r->dest_port);
350 fwd_ipt_add_format(b, " -j ACCEPT");
354 static void fwd_ipt_rule_create(struct fwd_data *d)
356 struct fwd_rule *r = &d->section.rule;
357 struct fwd_ipt_rulebuf *b;
359 b = fwd_ipt_init("filter");
362 fwd_ipt_add_format(b, " -A zone_%s_forward", r->src->name);
364 fwd_ipt_add_format(b, " -A zone_%s", r->src->name);
366 fwd_ipt_add_proto(b, r->proto);
367 fwd_ipt_add_icmptype(b, r->icmp_type);
368 fwd_ipt_add_srcmac(b, r->src_mac);
369 fwd_ipt_add_srcaddr(b, r->src_ip);
370 fwd_ipt_add_srcport(b, r->src_port);
371 fwd_ipt_add_destaddr(b, r->dest_ip);
372 fwd_ipt_add_destport(b, r->dest_port);
375 fwd_ipt_add_format(b, " -j zone_%s_%s",
376 r->dest->name, fwd_str_target(r->target));
378 fwd_ipt_add_format(b, " -j %s", fwd_str_target(r->target));
384 static struct fwd_network_list *
385 fwd_lookup_network(struct fwd_network_list *n, const char *net)
387 struct fwd_network_list *e;
390 for( e = n; e; e = e->next )
391 if( !strcmp(e->name, net) )
397 static struct fwd_addr_list *
398 fwd_lookup_addr(struct fwd_addr_list *a, const char *ifname)
400 struct fwd_addr_list *e;
403 for( e = a; e; e = e->next )
404 if( !strcmp(e->ifname, ifname) )
411 void fwd_ipt_build_ruleset(struct fwd_handle *h)
415 for( e = h->conf; e; e = e->next )
420 printf("\n## DEFAULTS\n");
421 fwd_ipt_defaults_create(e);
425 printf("\n## ZONE %s\n", e->section.zone.name);
426 fwd_ipt_zone_create(e);
430 printf("\n## FORWARD %s -> %s\n",
431 e->section.forwarding.src
432 ? e->section.forwarding.src->name : "(all)",
433 e->section.forwarding.dest
434 ? e->section.forwarding.dest->name : "(all)");
435 fwd_ipt_forwarding_create(e);
439 printf("\n## REDIRECT %s\n", e->section.forwarding.src->name);
440 fwd_ipt_redirect_create(e);
444 printf("\n## RULE %s\n", e->section.rule.src->name);
445 fwd_ipt_rule_create(e);
449 printf("\n## INCLUDE %s\n", e->section.include.path);
455 void fwd_ipt_addif(struct fwd_handle *h, const char *net)
459 struct fwd_addr_list *a;
460 struct fwd_network_list *n;
462 for( e = h->conf; e; e = e->next )
464 if( (e->type != FWD_S_ZONE) ||
465 !(n = fwd_lookup_network(e->section.zone.networks, net)) ||
466 !(a = fwd_lookup_addr(h->addrs, n->ifname)) )
469 z = &e->section.zone;
471 printf("\n## NETWORK %s (%s - %s/%u)\n",
473 inet_ntoa(a->ipaddr.v4), a->prefix
476 fwd_ipt_exec_format("filter", " -A input -i %s -j zone_%s",
479 fwd_ipt_exec_format("filter",
480 " -I zone_%s_MSSFIX 1 -o %s -p tcp --tcp-flags SYN,RST SYN"
481 " -j TCPMSS --clamp-mss-to-pmtu",
484 fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -o %s -j ACCEPT",
487 fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -o %s -j DROP",
490 fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -o %s -j reject",
493 fwd_ipt_exec_format("filter", " -I zone_%s_ACCEPT 1 -i %s -j ACCEPT",
496 fwd_ipt_exec_format("filter", " -I zone_%s_DROP 1 -i %s -j DROP",
499 fwd_ipt_exec_format("filter", " -I zone_%s_REJECT 1 -i %s -j reject",
502 fwd_ipt_exec_format("filter",
503 " -I zone_%s_nat 1 -t nat -o %s -j MASQUERADE",
506 fwd_ipt_exec_format("filter",
507 " -I PREROUTING 1 -t nat -i %s -j zone_%s_prerouting",
510 fwd_ipt_exec_format("filter", " -A forward -i %s -j zone_%s_forward",
513 fwd_ipt_exec_format("raw", " -I PREROUTING 1 -i %s -j zone_%s_notrack",