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",