rc, iptables, web UI: QoS: add DSCP matching criteria
[tomato.git] / release / src / router / rc / firewall.c
blobbc418865151a794999af0128f0032de314283109
1 /*
3 Copyright 2003-2005, CyberTAN Inc. All Rights Reserved
5 This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
6 the contents of this file may not be disclosed to third parties,
7 copied or duplicated in any form without the prior written
8 permission of CyberTAN Inc.
10 This software should be used as a reference only, and it not
11 intended for production use!
13 THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
14 KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
15 SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
16 FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
21 Modified for Tomato Firmware
22 Portions, Copyright (C) 2006-2009 Jonathan Zarate
26 #include "rc.h"
28 #include <stdarg.h>
29 #include <arpa/inet.h>
30 #include <dirent.h>
32 wanface_list_t wanfaces;
33 char lanface[IFNAMSIZ + 1];
34 #ifdef TCONFIG_IPV6
35 char wan6face[IFNAMSIZ + 1];
36 #endif
37 char lan_cclass[sizeof("xxx.xxx.xxx.") + 1];
39 #ifdef DEBUG_IPTFILE
40 static int debug_only = 0;
41 #endif
43 static int gateway_mode;
44 static int remotemanage;
45 static int wanup;
47 const char *chain_in_drop;
48 const char *chain_in_accept;
49 const char *chain_out_drop;
50 const char *chain_out_accept;
51 const char *chain_out_reject;
53 const char chain_wan_prerouting[] = "WANPREROUTING";
54 const char ipt_fname[] = "/etc/iptables";
55 FILE *ipt_file;
57 #ifdef TCONFIG_IPV6
58 const char ip6t_fname[] = "/etc/ip6tables";
59 FILE *ip6t_file;
60 #endif
64 struct {
65 } firewall_data;
68 // -----------------------------------------------------------------------------
71 void enable_ip_forward(void)
74 ip_forward - BOOLEAN
75 0 - disabled (default)
76 not 0 - enabled
78 Forward Packets between interfaces.
80 This variable is special, its change resets all configuration
81 parameters to their default state (RFC1122 for hosts, RFC1812
82 for routers)
84 f_write_string("/proc/sys/net/ipv4/ip_forward", "1", 0, 0);
86 #ifdef TCONFIG_IPV6
87 if (ipv6_enabled()) {
88 f_write_string("/proc/sys/net/ipv6/conf/default/forwarding", "1", 0, 0);
89 f_write_string("/proc/sys/net/ipv6/conf/all/forwarding", "1", 0, 0);
91 #endif
95 // -----------------------------------------------------------------------------
98 static int ip2cclass(char *ipaddr, char *new, int count)
100 int ip[4];
102 if (sscanf(ipaddr,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]) != 4) return 0;
103 return snprintf(new, count, "%d.%d.%d.",ip[0],ip[1],ip[2]);
108 static int dmz_dst(char *s)
110 struct in_addr ia;
111 char *p;
112 int n;
114 if (nvram_get_int("dmz_enable") <= 0) return 0;
116 p = nvram_safe_get("dmz_ipaddr");
117 if ((ia.s_addr = inet_addr(p)) == (in_addr_t)-1) {
118 if (((n = atoi(p)) <= 0) || (n >= 255)) return 0;
119 if (s) sprintf(s, "%s%d", lan_cclass, n);
120 return 1;
123 if (s) strcpy(s, inet_ntoa(ia));
124 return 1;
127 void ipt_addr(char *addr, int maxlen, const char *s, const char *dir)
129 char p[32];
131 if ((*s) && (*dir))
133 if (sscanf(s, "%[0-9.]-%[0-9.]", p, p) == 2)
134 snprintf(addr, maxlen, "-m iprange --%s-range %s", dir, s);
135 else
136 snprintf(addr, maxlen, "-%c %s", dir[0], s);
138 else
139 *addr = 0;
142 static inline void ipt_source(const char *s, char *src)
144 ipt_addr(src, 64, s, "src");
148 static void get_src(const char *nv, char *src)
150 char *p;
152 if (((p = nvram_get(nv)) != NULL) && (*p) && (strlen(p) < 32)) {
153 sprintf(src, "-%s %s", strchr(p, '-') ? "m iprange --src-range" : "s", p);
155 else {
156 *src = 0;
161 void ipt_write(const char *format, ...)
163 va_list args;
165 va_start(args, format);
166 vfprintf(ipt_file, format, args);
167 va_end(args);
170 void ip6t_write(const char *format, ...)
172 #ifdef TCONFIG_IPV6
173 va_list args;
175 va_start(args, format);
176 vfprintf(ip6t_file, format, args);
177 va_end(args);
178 #endif
181 // -----------------------------------------------------------------------------
183 int ipt_dscp(const char *v, char *opt)
185 unsigned int n;
187 if (*v == 0) {
188 *opt = 0;
189 return 0;
192 n = strtoul(v, NULL, 0);
193 if (n > 63) n = 63;
194 sprintf(opt, " -m dscp --dscp 0x%02X", n);
196 #ifdef LINUX26
197 modprobe("xt_dscp");
198 #else
199 modprobe("ipt_dscp");
200 #endif
201 return 1;
204 // -----------------------------------------------------------------------------
207 int ipt_ipp2p(const char *v, char *opt)
209 int n = atoi(v);
211 if (n == 0) {
212 *opt = 0;
213 return 0;
216 strcpy(opt, "-m ipp2p ");
217 if ((n & 0xFFF) == 0xFFF) {
218 strcat(opt, "--ipp2p");
220 else {
221 // x12
222 if (n & 0x0001) strcat(opt, "--apple ");
223 if (n & 0x0002) strcat(opt, "--ares ");
224 if (n & 0x0004) strcat(opt, "--bit ");
225 if (n & 0x0008) strcat(opt, "--dc ");
226 if (n & 0x0010) strcat(opt, "--edk ");
227 if (n & 0x0020) strcat(opt, "--gnu ");
228 if (n & 0x0040) strcat(opt, "--kazaa ");
229 if (n & 0x0080) strcat(opt, "--mute ");
230 if (n & 0x0100) strcat(opt, "--soul ");
231 if (n & 0x0200) strcat(opt, "--waste ");
232 if (n & 0x0400) strcat(opt, "--winmx ");
233 if (n & 0x0800) strcat(opt, "--xdcc ");
236 modprobe("ipt_ipp2p");
237 return 1;
241 // -----------------------------------------------------------------------------
244 char **layer7_in;
246 // This L7 matches inbound traffic, caches the results, then the L7 outbound
247 // should read the cached result and set the appropriate marks -- zzz
248 void ipt_layer7_inbound(void)
250 int en, i;
251 char **p;
253 if (!layer7_in) return;
255 en = nvram_match("nf_l7in", "1");
256 if (en) {
257 ipt_write(":L7in - [0:0]\n");
258 for (i = 0; i < wanfaces.count; ++i) {
259 if (*(wanfaces.iface[i].name)) {
260 ipt_write("-A FORWARD -i %s -j L7in\n",
261 wanfaces.iface[i].name);
266 p = layer7_in;
267 while (*p) {
268 if (en) ipt_write("-A L7in %s -j RETURN\n", *p);
269 free(*p);
270 ++p;
272 free(layer7_in);
273 layer7_in = NULL;
276 int ipt_layer7(const char *v, char *opt)
278 char s[128];
279 char *path;
281 *opt = 0;
282 if (*v == 0) return 0;
283 if (strlen(v) > 32) return -1;
285 path = "/etc/l7-extra";
286 sprintf(s, "%s/%s.pat", path, v);
287 if (!f_exists(s)) {
288 path = "/etc/l7-protocols";
289 sprintf(s, "%s/%s.pat", path, v);
290 if (!f_exists(s)) {
291 syslog(LOG_ERR, "L7 %s was not found", v);
292 return -1;
296 sprintf(opt, "-m layer7 --l7dir %s --l7proto %s", path, v);
298 if (nvram_match("nf_l7in", "1")) {
299 if (!layer7_in) layer7_in = calloc(51, sizeof(char *));
300 if (layer7_in) {
301 char **p;
303 p = layer7_in;
304 while (*p) {
305 if (strcmp(*p, opt) == 0) return 1;
306 ++p;
308 if (((p - layer7_in) / sizeof(char *)) < 50) *p = strdup(opt);
312 #ifdef LINUX26
313 modprobe("xt_layer7");
314 #else
315 modprobe("ipt_layer7");
316 #endif
317 return 1;
321 // -----------------------------------------------------------------------------
323 static void save_webmon(void)
325 system("cp /proc/webmon_recent_domains /var/webmon/domain");
326 system("cp /proc/webmon_recent_searches /var/webmon/search");
329 static void ipt_webmon(int do_ip6t)
331 int wmtype, clear, i;
332 char t[512];
333 char src[64];
334 char *p, *c;
336 if (!nvram_get_int("log_wm")) return;
337 wmtype = nvram_get_int("log_wmtype");
338 clear = nvram_get_int("log_wmclear");
340 ip46t_cond_write(do_ip6t, ":monitor - [0:0]\n");
342 #ifdef TCONFIG_IPV6
343 // TODO: check for the IP address type (v4/v6)
344 // (currently IPv6 source addresses are not filtered)
345 if (do_ip6t)
346 ip6t_write("-A FORWARD -o %s -j monitor\n", wan6face);
347 else {
348 #endif
349 // include IPs
350 strlcpy(t, wmtype == 1 ? nvram_safe_get("log_wmip") : "", sizeof(t));
351 p = t;
352 do {
353 if ((c = strchr(p, ',')) != NULL) *c = 0;
354 ipt_source(p, src);
356 for (i = 0; i < wanfaces.count; ++i) {
357 if (*(wanfaces.iface[i].name)) {
358 ipt_write("-A FORWARD -o %s %s -j monitor\n",
359 wanfaces.iface[i].name, src);
363 if (!c) break;
364 p = c + 1;
365 } while (*p);
366 #ifdef TCONFIG_IPV6
368 #endif
370 // exclude IPs
371 if (wmtype == 2 && !do_ip6t) {
372 strlcpy(t, nvram_safe_get("log_wmip"), sizeof(t));
373 p = t;
374 do {
375 if ((c = strchr(p, ',')) != NULL) *c = 0;
376 ipt_source(p, src);
377 if (*src) ipt_write("-A monitor %s -j RETURN\n", src);
378 if (!c) break;
379 p = c + 1;
380 } while (*p);
383 ip46t_cond_write(do_ip6t,
384 "-A monitor -p tcp -m webmon "
385 "--max_domains %d --max_searches %d %s %s -j RETURN\n",
386 nvram_get_int("log_wmdmax") ? : 1, nvram_get_int("log_wmsmax") ? : 1,
387 (clear & 1) == 0 ? "--domain_load_file /var/webmon/domain" : "--clear_domain",
388 (clear & 2) == 0 ? "--search_load_file /var/webmon/search" : "--clear_search");
390 #ifdef LINUX26
391 modprobe("xt_webmon");
392 #else
393 modprobe("ipt_webmon");
394 #endif
398 // -----------------------------------------------------------------------------
399 // MANGLE
400 // -----------------------------------------------------------------------------
402 static void mangle_table(void)
404 int ttl;
405 char *p, *wanface;
407 ip46t_write(
408 "*mangle\n"
409 ":PREROUTING ACCEPT [0:0]\n"
410 ":OUTPUT ACCEPT [0:0]\n");
412 if (wanup) {
414 ipt_qos();
416 p = nvram_safe_get("nf_ttl");
417 if (strncmp(p, "c:", 2) == 0) {
418 p += 2;
419 ttl = atoi(p);
420 p = (ttl >= 0 && ttl <= 255) ? "set" : NULL;
422 else if ((ttl = atoi(p)) != 0) {
423 if (ttl > 0) {
424 p = "inc";
426 else {
427 ttl = -ttl;
428 p = "dec";
430 if (ttl > 255) p = NULL;
432 else p = NULL;
434 if (p) {
435 #ifdef LINUX26
436 modprobe("xt_HL");
437 #else
438 modprobe("ipt_TTL");
439 #endif
440 // set TTL on primary WAN iface only
441 wanface = wanfaces.iface[0].name;
442 ip46t_write(
443 "-I PREROUTING -i %s -j TTL --ttl-%s %d\n"
444 "-I POSTROUTING -o %s -j TTL --ttl-%s %d\n",
445 wanface, p, ttl,
446 wanface, p, ttl);
450 ip46t_write("COMMIT\n");
455 // -----------------------------------------------------------------------------
456 // NAT
457 // -----------------------------------------------------------------------------
459 static void nat_table(void)
461 char lanaddr[32];
462 char lanmask[32];
463 char dst[64];
464 char src[64];
465 char t[512];
466 char *p, *c;
467 int i;
469 ipt_write("*nat\n"
470 ":PREROUTING ACCEPT [0:0]\n"
471 ":POSTROUTING ACCEPT [0:0]\n"
472 ":OUTPUT ACCEPT [0:0]\n"
473 ":%s - [0:0]\n",
474 chain_wan_prerouting);
476 if (gateway_mode) {
477 strlcpy(lanaddr, nvram_safe_get("lan_ipaddr"), sizeof(lanaddr));
478 strlcpy(lanmask, nvram_safe_get("lan_netmask"), sizeof(lanmask));
480 for (i = 0; i < wanfaces.count; ++i) {
481 if (*(wanfaces.iface[i].name)) {
482 // chain_wan_prerouting
483 if (wanup)
484 ipt_write("-A PREROUTING -d %s -j %s\n",
485 wanfaces.iface[i].ip, chain_wan_prerouting);
487 // Drop incoming packets which destination IP address is to our LAN side directly
488 ipt_write("-A PREROUTING -i %s -d %s/%s -j DROP\n",
489 wanfaces.iface[i].name,
490 lanaddr, lanmask); // note: ipt will correct lanaddr
494 if (wanup) {
495 if (nvram_match("dns_intcpt", "1")) {
496 ipt_write("-A PREROUTING -p udp -s %s/%s ! -d %s/%s --dport 53 -j DNAT --to-destination %s\n",
497 lanaddr, lanmask,
498 lanaddr, lanmask,
499 lanaddr);
502 // ICMP packets are always redirected to INPUT chains
503 ipt_write("-A %s -p icmp -j DNAT --to-destination %s\n", chain_wan_prerouting, lanaddr);
505 ipt_forward(IPT_TABLE_NAT);
506 ipt_triggered(IPT_TABLE_NAT);
509 if (nvram_get_int("upnp_enable") & 3) {
510 ipt_write(":upnp - [0:0]\n");
511 if (wanup) {
512 // ! for loopback (all) to work
513 ipt_write("-A %s -j upnp\n", chain_wan_prerouting);
515 else {
516 for (i = 0; i < wanfaces.count; ++i) {
517 if (*(wanfaces.iface[i].name)) {
518 ipt_write("-A PREROUTING -i %s -j upnp\n", wanfaces.iface[i].name);
524 if (wanup) {
525 if (dmz_dst(dst)) {
526 strlcpy(t, nvram_safe_get("dmz_sip"), sizeof(t));
527 p = t;
528 do {
529 if ((c = strchr(p, ',')) != NULL) *c = 0;
530 ipt_source(p, src);
531 ipt_write("-A %s %s -j DNAT --to-destination %s\n", chain_wan_prerouting, src, dst);
532 if (!c) break;
533 p = c + 1;
534 } while (*p);
538 p = "";
539 #ifdef TCONFIG_IPV6
540 switch (get_ipv6_service()) {
541 case IPV6_6IN4:
542 // avoid NATing proto-41 packets when using 6in4 tunnel
543 p = "-p ! 41";
544 break;
546 #endif
548 for (i = 0; i < wanfaces.count; ++i) {
549 if (*(wanfaces.iface[i].name)) {
550 if ((!wanup) || (nvram_get_int("net_snat") != 1))
551 ipt_write("-A POSTROUTING %s -o %s -j MASQUERADE\n", p, wanfaces.iface[i].name);
552 else
553 ipt_write("-A POSTROUTING %s -o %s -j SNAT --to-source %s\n", p, wanfaces.iface[i].name, wanfaces.iface[i].ip);
557 switch (nvram_get_int("nf_loopback")) {
558 case 1: // 1 = forwarded-only
559 case 2: // 2 = disable
560 break;
561 default: // 0 = all (same as block_loopback=0)
562 ipt_write("-A POSTROUTING -o %s -s %s/%s -d %s/%s -j SNAT --to-source %s\n",
563 lanface,
564 lanaddr, lanmask,
565 lanaddr, lanmask,
566 lanaddr);
567 break;
570 ipt_write("COMMIT\n");
573 // -----------------------------------------------------------------------------
574 // FILTER
575 // -----------------------------------------------------------------------------
577 static void filter_input(void)
579 char s[64];
580 char t[512];
581 char *en;
582 char *sec;
583 char *hit;
584 int n;
585 char *p, *c;
587 if ((nvram_get_int("nf_loopback") != 0) && (wanup)) { // 0 = all
588 for (n = 0; n < wanfaces.count; ++n) {
589 if (*(wanfaces.iface[n].name)) {
590 ipt_write("-A INPUT -i %s -d %s -j DROP\n", lanface, wanfaces.iface[n].ip);
595 ipt_write(
596 "-A INPUT -m state --state INVALID -j %s\n"
597 "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n",
598 chain_in_drop);
601 strlcpy(s, nvram_safe_get("ne_shlimit"), sizeof(s));
602 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && ((n = atoi(en) & 3) != 0)) {
604 ? what if the user uses the start button in GUI ?
605 if (nvram_get_int("telnetd_eas"))
606 if (nvram_get_int("sshd_eas"))
608 #ifdef LINUX26
609 modprobe("xt_recent");
610 #else
611 modprobe("ipt_recent");
612 #endif
614 ipt_write(
615 "-N shlimit\n"
616 "-A shlimit -m recent --set --name shlimit\n"
617 "-A shlimit -m recent --update --hitcount %d --seconds %s --name shlimit -j %s\n",
618 atoi(hit) + 1, sec, chain_in_drop);
620 if (n & 1) {
621 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_port"));
622 if (nvram_get_int("sshd_remote") && nvram_invmatch("sshd_rport", nvram_safe_get("sshd_port"))) {
623 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_rport"));
626 if (n & 2) ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("telnetd_port"));
629 #ifdef TCONFIG_FTP
630 strlcpy(s, nvram_safe_get("ftp_limit"), sizeof(s));
631 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && (atoi(en)) && (nvram_get_int("ftp_enable") == 1)) {
632 #ifdef LINUX26
633 modprobe("xt_recent");
634 #else
635 modprobe("ipt_recent");
636 #endif
638 ipt_write(
639 "-N ftplimit\n"
640 "-A ftplimit -m recent --set --name ftp\n"
641 "-A ftplimit -m recent --update --hitcount %d --seconds %s --name ftp -j %s\n",
642 atoi(hit) + 1, sec, chain_in_drop);
643 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j ftplimit\n", nvram_safe_get("ftp_port"));
645 #endif
647 ipt_write(
648 "-A INPUT -i %s -j ACCEPT\n"
649 "-A INPUT -i lo -j ACCEPT\n",
650 lanface);
652 #ifdef TCONFIG_IPV6
653 switch (get_ipv6_service()) {
654 case IPV6_6IN4:
655 // Accept ICMP requests from the remote tunnel endpoint
656 if ((p = nvram_get("ipv6_tun_v4end")) && *p && strcmp(p, "0.0.0.0") != 0)
657 ipt_write("-A INPUT -p icmp -s %s -j %s\n", p, chain_in_accept);
658 ipt_write("-A INPUT -p 41 -j %s\n", chain_in_accept);
659 break;
661 #endif
663 // ICMP request from WAN interface
664 if (nvram_match("block_wan", "0")) {
665 // allow ICMP packets to be received, but restrict the flow to avoid ping flood attacks
666 ipt_write("-A INPUT -p icmp -m limit --limit 1/second -j %s\n", chain_in_accept);
667 // allow udp traceroute packets
668 ipt_write("-A INPUT -p udp -m udp --dport 33434:33534 -m limit --limit 5/second -j %s\n", chain_in_accept);
671 /* Accept incoming packets from broken dhcp servers, which are sending replies
672 * from addresses other than used for query. This could lead to a lower level
673 * of security, so allow to disable it via nvram variable.
675 if (nvram_invmatch("dhcp_pass", "0") && using_dhcpc()) {
676 ipt_write("-A INPUT -p udp --sport 67 --dport 68 -j %s\n", chain_in_accept);
679 strlcpy(t, nvram_safe_get("rmgt_sip"), sizeof(t));
680 p = t;
681 do {
682 if ((c = strchr(p, ',')) != NULL) *c = 0;
684 ipt_source(p, s);
686 if (remotemanage) {
687 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
688 s, nvram_safe_get("http_wanport"), chain_in_accept);
691 if (nvram_get_int("sshd_remote")) {
692 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
693 s, nvram_safe_get("sshd_rport"), chain_in_accept);
696 if (!c) break;
697 p = c + 1;
698 } while (*p);
701 #ifdef TCONFIG_FTP // !!TB - FTP Server
702 if (nvram_match("ftp_enable", "1")) { // FTP WAN access enabled
703 strlcpy(t, nvram_safe_get("ftp_sip"), sizeof(t));
704 p = t;
705 do {
706 if ((c = strchr(p, ',')) != NULL) *c = 0;
707 ipt_source(p, s);
709 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
710 s, nvram_safe_get("ftp_port"), chain_in_accept);
712 if (!c) break;
713 p = c + 1;
714 } while (*p);
716 #endif
718 // IGMP query from WAN interface
719 if (nvram_match("multicast_pass", "1")) {
720 ipt_write("-A INPUT -p igmp -d 224.0.0.0/4 -j ACCEPT\n");
721 ipt_write("-A INPUT -p udp -d 224.0.0.0/4 ! --dport 1900 -j ACCEPT\n");
724 // Routing protocol, RIP, accept
725 if (nvram_invmatch("dr_wan_rx", "0")) {
726 ipt_write("-A INPUT -p udp -m udp --dport 520 -j ACCEPT\n");
729 // if logging
730 if (*chain_in_drop == 'l') {
731 ipt_write( "-A INPUT -j %s\n", chain_in_drop);
734 // default policy: DROP
737 // clamp TCP MSS to PMTU of WAN interface
738 static void clampmss(void)
740 #if 1
741 ipt_write("-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu\n");
742 #else
743 int rmtu = nvram_get_int("wan_run_mtu");
744 ipt_write("-A FORWARD -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss %d: -j TCPMSS ", rmtu - 39);
745 if (rmtu < 576) {
746 ipt_write("--clamp-mss-to-pmtu\n");
748 else {
749 ipt_write("--set-mss %d\n", rmtu - 40);
751 #endif
754 static void filter_forward(void)
756 char dst[64];
757 char src[64];
758 char t[512];
759 char *p, *c;
760 int i;
762 ipt_write(
763 "-A FORWARD -i %s -o %s -j ACCEPT\n" // accept all lan to lan
764 "-A FORWARD -m state --state INVALID -j DROP\n", // drop if INVALID state
765 lanface, lanface);
767 // clamp tcp mss to pmtu
768 clampmss();
770 if (wanup) {
771 ipt_restrictions();
772 ipt_layer7_inbound();
775 ipt_webmon(0);
777 ipt_write(
778 ":wanin - [0:0]\n"
779 ":wanout - [0:0]\n"
780 "-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT\n"); // already established or related (via helper)
782 for (i = 0; i < wanfaces.count; ++i) {
783 if (*(wanfaces.iface[i].name)) {
784 ipt_write(
785 "-A FORWARD -i %s -j wanin\n" // generic from wan
786 "-A FORWARD -o %s -j wanout\n", // generic to wan
787 wanfaces.iface[i].name, wanfaces.iface[i].name);
791 ipt_write("-A FORWARD -i %s -j %s\n", // from lan
792 lanface, chain_out_accept);
794 if (nvram_get_int("upnp_enable") & 3) {
795 ipt_write(":upnp - [0:0]\n");
796 for (i = 0; i < wanfaces.count; ++i) {
797 if (*(wanfaces.iface[i].name)) {
798 ipt_write("-A FORWARD -i %s -j upnp\n",
799 wanfaces.iface[i].name);
804 if (wanup) {
805 if (nvram_match("multicast_pass", "1")) {
806 ipt_write("-A wanin -p udp -d 224.0.0.0/4 -j %s\n", chain_in_accept);
808 ipt_triggered(IPT_TABLE_FILTER);
809 ipt_forward(IPT_TABLE_FILTER);
811 if (dmz_dst(dst)) {
812 strlcpy(t, nvram_safe_get("dmz_sip"), sizeof(t));
813 p = t;
814 do {
815 if ((c = strchr(p, ',')) != NULL) *c = 0;
816 ipt_source(p, src);
817 ipt_write("-A FORWARD -o %s %s -d %s -j %s\n", lanface, src, dst, chain_in_accept);
818 if (!c) break;
819 p = c + 1;
820 } while (*p);
825 // default policy: DROP
828 static void filter_log(void)
830 int n;
831 char limit[128];
833 n = nvram_get_int("log_limit");
834 if ((n >= 1) && (n <= 9999)) {
835 sprintf(limit, "-m limit --limit %d/m", n);
837 else {
838 limit[0] = 0;
841 #ifdef TCONFIG_IPV6
842 modprobe("ip6t_LOG");
843 #endif
844 if ((*chain_in_drop == 'l') || (*chain_out_drop == 'l')) {
845 ip46t_write(
846 ":logdrop - [0:0]\n"
847 "-A logdrop -m state --state NEW %s -j LOG --log-prefix \"DROP \" --log-tcp-options --log-ip-options\n"
848 "-A logdrop -j DROP\n"
849 ":logreject - [0:0]\n"
850 "-A logreject %s -j LOG --log-prefix \"REJECT \" --log-tcp-options --log-ip-options\n"
851 "-A logreject -p tcp -j REJECT --reject-with tcp-reset\n",
852 limit, limit);
854 if ((*chain_in_accept == 'l') || (*chain_out_accept == 'l')) {
855 ip46t_write(
856 ":logaccept - [0:0]\n"
857 "-A logaccept -m state --state NEW %s -j LOG --log-prefix \"ACCEPT \" --log-tcp-options --log-ip-options\n"
858 "-A logaccept -j ACCEPT\n",
859 limit);
863 #ifdef TCONFIG_IPV6
864 static void filter6_input(void)
866 char s[64];
867 char *en;
868 char *sec;
869 char *hit;
870 int n;
872 ip6t_write(
873 "-A INPUT -m rt --rt-type 0 -j %s\n"
874 /* "-A INPUT -m state --state INVALID -j %s\n" */
875 "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n",
876 chain_in_drop/*, chain_in_drop*/);
878 #ifdef LINUX26
879 modprobe("xt_length");
880 ip6t_write("-A INPUT -p ipv6-nonxt -m length --length 40 -j ACCEPT\n");
881 #endif
883 strlcpy(s, nvram_safe_get("ne_shlimit"), sizeof(s));
884 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && ((n = atoi(en) & 3) != 0)) {
885 #ifdef LINUX26
886 modprobe("xt_recent");
887 #else
888 modprobe("ipt_recent");
889 #endif
891 ip6t_write(
892 "-N shlimit\n"
893 "-A shlimit -m recent --set --name shlimit\n"
894 "-A shlimit -m recent --update --hitcount %d --seconds %s --name shlimit -j %s\n",
895 atoi(hit) + 1, sec, chain_in_drop);
897 if (n & 1) {
898 ip6t_write("-A INPUT -i %s -p tcp --dport %s -m state --state NEW -j shlimit\n", lanface, nvram_safe_get("sshd_port"));
899 if (nvram_get_int("sshd_remote") && nvram_invmatch("sshd_rport", nvram_safe_get("sshd_port"))) {
900 ip6t_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_rport"));
903 if (n & 2) ip6t_write("-A INPUT -i %s -p tcp --dport %s -m state --state NEW -j shlimit\n", lanface, nvram_safe_get("telnetd_port"));
906 #ifdef TCONFIG_FTP
907 strlcpy(s, nvram_safe_get("ftp_limit"), sizeof(s));
908 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && (atoi(en)) && (nvram_get_int("ftp_enable") == 1)) {
909 #ifdef LINUX26
910 modprobe("xt_recent");
911 #else
912 modprobe("ipt_recent");
913 #endif
915 ip6t_write(
916 "-N ftplimit\n"
917 "-A ftplimit -m recent --set --name ftp\n"
918 "-A ftplimit -m recent --update --hitcount %d --seconds %s --name ftp -j %s\n",
919 atoi(hit) + 1, sec, chain_in_drop);
920 ip6t_write("-A INPUT -p tcp --dport %s -m state --state NEW -j ftplimit\n", nvram_safe_get("ftp_port"));
922 #endif // TCONFIG_FTP
924 ip6t_write(
925 "-A INPUT -i %s -j ACCEPT\n" // anything coming from LAN
926 "-A INPUT -i lo -j ACCEPT\n",
927 lanface );
929 switch (get_ipv6_service()) {
930 case IPV6_NATIVE_DHCP:
931 // allow responses from the dhcpv6 server
932 ip6t_write("-A INPUT -p udp --dport 546 -j %s\n", chain_in_accept);
933 break;
936 // ICMPv6 rules
937 const int allowed_icmpv6[6] = { 1, 2, 3, 4, 128, 129 };
938 for (n = 0; n < sizeof(allowed_icmpv6)/sizeof(int); n++) {
939 ip6t_write("-A INPUT -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_icmpv6[n], chain_in_accept);
942 // Remote Managment
943 // TODO: create list for allowed remote ipv6 addresses?
944 // Currently: disabled if there is a non-empty list of allowed ipv4 addresses,
945 // otherwise unrestricted
946 if (strlen(nvram_safe_get("rmgt_sip")) == 0) {
947 if (remotemanage) {
948 ip6t_write("-A INPUT -p tcp -m tcp --dport %s -j %s\n",
949 nvram_safe_get("http_wanport"), chain_in_accept);
952 if (nvram_get_int("sshd_remote")) {
953 ip6t_write("-A INPUT -p tcp -m tcp --dport %s -j %s\n",
954 nvram_safe_get("sshd_rport"), chain_in_accept);
958 // FTP server
959 // TODO: create list for allowed remote ipv6 addresses? (see above)...
960 #ifdef TCONFIG_FTP
961 if (nvram_match("ftp_enable", "1")) { // FTP WAN access enabled
962 if (strlen(nvram_safe_get("ftp_sip")) == 0) {
963 ip6t_write("-A INPUT -p tcp -m tcp --dport %s -j %s\n",
964 nvram_safe_get("ftp_port"), chain_in_accept);
967 #endif
969 // if logging
970 if (*chain_in_drop == 'l') {
971 ip6t_write( "-A INPUT -j %s\n", chain_in_drop);
974 // default policy: DROP
977 static void filter6_forward(void)
979 int n;
981 ip6t_write(
982 "-A FORWARD -m rt --rt-type 0 -j DROP\n"
983 "-A FORWARD -i %s -o %s -j ACCEPT\n" // accept all lan to lan
984 /*"-A FORWARD -m state --state INVALID -j DROP\n"*/, // drop if INVALID state
985 lanface, lanface);
987 // Filter out invalid WAN->WAN connections
988 ip6t_write("-A FORWARD -o %s ! -i %s -j %s\n", wan6face, lanface, chain_in_drop);
990 #ifdef LINUX26
991 modprobe("xt_length");
992 ip6t_write("-A FORWARD -p ipv6-nonxt -m length --length 40 -j ACCEPT\n");
993 #endif
995 // clamp tcp mss to pmtu TODO?
996 // clampmss();
998 // TODO: support l7, access restrictions on ipv6?
1000 if (wanup) {
1001 ipt_restrictions();
1002 ipt_layer7_inbound();
1005 #ifdef LINUX26
1006 ipt_webmon(1);
1007 #endif
1009 ip6t_write(
1010 ":wanin - [0:0]\n"
1011 ":wanout - [0:0]\n"
1012 "-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT\n" // already established or related (via helper)
1013 "-A FORWARD -i %s -j wanin\n" // generic from wan
1014 "-A FORWARD -o %s -j wanout\n" // generic to wan
1015 "-A FORWARD -i %s -j %s\n", // from lan
1016 wan6face, wan6face, lanface, chain_out_accept);
1018 // ICMPv6 rules
1019 const int allowed_icmpv6[6] = { 1, 2, 3, 4, 128, 129 };
1020 for (n = 0; n < sizeof(allowed_icmpv6)/sizeof(int); n++) {
1021 ip6t_write("-A FORWARD -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_icmpv6[n], chain_in_accept);
1024 if (wanup) {
1025 //ipt_triggered(IPT_TABLE_FILTER);
1026 ip6t_forward();
1029 // default policy: DROP
1032 #endif
1034 static void filter_table(void)
1036 ip46t_write(
1037 "*filter\n"
1038 ":INPUT DROP [0:0]\n"
1039 ":OUTPUT ACCEPT [0:0]\n"
1042 filter_log();
1044 filter_input();
1045 #ifdef TCONFIG_IPV6
1046 filter6_input();
1047 ip6t_write("-A OUTPUT -m rt --rt-type 0 -j %s\n", chain_in_drop);
1048 #endif
1050 if ((gateway_mode) || (nvram_match("wk_mode_x", "1"))) {
1051 ip46t_write(":FORWARD DROP [0:0]\n");
1052 filter_forward();
1053 #ifdef TCONFIG_IPV6
1054 filter6_forward();
1055 #endif
1057 else {
1058 ip46t_write(":FORWARD ACCEPT [0:0]\n");
1059 clampmss();
1061 ip46t_write("COMMIT\n");
1065 // -----------------------------------------------------------------------------
1067 int start_firewall(void)
1069 DIR *dir;
1070 struct dirent *dirent;
1071 char s[256];
1072 char *c, *wanface;
1073 int n;
1074 int wanproto;
1075 char *iptrestore_argv[] = { "iptables-restore", (char *)ipt_fname, NULL };
1076 #ifdef TCONFIG_IPV6
1077 char *ip6trestore_argv[] = { "ip6tables-restore", (char *)ip6t_fname, NULL };
1078 #endif
1080 simple_lock("firewall");
1081 simple_lock("restrictions");
1083 wanproto = get_wan_proto();
1084 wanup = check_wanup();
1086 f_write_string("/proc/sys/net/ipv4/tcp_syncookies", nvram_get_int("ne_syncookies") ? "1" : "0", 0, 0);
1088 /* NAT performance tweaks
1089 * These values can be overriden later if needed via firewall script
1091 f_write_string("/proc/sys/net/core/netdev_max_backlog", "3072", 0, 0);
1092 f_write_string("/proc/sys/net/core/somaxconn", "3072", 0, 0);
1093 f_write_string("/proc/sys/net/ipv4/tcp_max_syn_backlog", "8192", 0, 0);
1094 f_write_string("/proc/sys/net/ipv4/tcp_fin_timeout", "30", 0, 0);
1095 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_intvl", "24", 0, 0);
1096 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_probes", "3", 0, 0);
1097 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_time", "1800", 0, 0);
1098 f_write_string("/proc/sys/net/ipv4/tcp_retries2", "5", 0, 0);
1099 f_write_string("/proc/sys/net/ipv4/tcp_syn_retries", "3", 0, 0);
1100 f_write_string("/proc/sys/net/ipv4/tcp_synack_retries", "3", 0, 0);
1101 f_write_string("/proc/sys/net/ipv4/tcp_tw_recycle", "1", 0, 0);
1102 f_write_string("/proc/sys/net/ipv4/tcp_tw_reuse", "1", 0, 0);
1104 /* DoS-related tweaks */
1105 f_write_string("/proc/sys/net/ipv4/icmp_ignore_bogus_error_responses", "1", 0, 0);
1106 f_write_string("/proc/sys/net/ipv4/tcp_rfc1337", "1", 0, 0);
1107 f_write_string("/proc/sys/net/ipv4/ip_local_port_range", "1024 65535", 0, 0);
1109 #ifdef TCONFIG_EMF
1110 /* Force IGMPv2 due EMF limitations */
1111 if (nvram_get_int("emf_enable")) {
1112 f_write_string("/proc/sys/net/ipv4/conf/default/force_igmp_version", "2", 0, 0);
1113 f_write_string("/proc/sys/net/ipv4/conf/all/force_igmp_version", "2", 0, 0);
1115 #endif
1117 n = nvram_get_int("log_in");
1118 chain_in_drop = (n & 1) ? "logdrop" : "DROP";
1119 chain_in_accept = (n & 2) ? "logaccept" : "ACCEPT";
1121 n = nvram_get_int("log_out");
1122 chain_out_drop = (n & 1) ? "logdrop" : "DROP";
1123 chain_out_reject = (n & 1) ? "logreject" : "REJECT --reject-with tcp-reset";
1124 chain_out_accept = (n & 2) ? "logaccept" : "ACCEPT";
1126 // if (nvram_match("nf_drop_reset", "1")) chain_out_drop = chain_out_reject;
1128 strlcpy(lanface, nvram_safe_get("lan_ifname"), IFNAMSIZ);
1130 memcpy(&wanfaces, get_wanfaces(), sizeof(wanfaces));
1131 wanface = wanfaces.iface[0].name;
1132 #ifdef TCONFIG_IPV6
1133 strlcpy(wan6face, get_wan6face(), sizeof(wan6face));
1134 #endif
1136 strlcpy(s, nvram_safe_get("lan_ipaddr"), sizeof(s));
1137 if ((c = strrchr(s, '.')) != NULL) *(c + 1) = 0;
1138 strlcpy(lan_cclass, s, sizeof(lan_cclass));
1141 block obviously spoofed IP addresses
1143 rp_filter - BOOLEAN
1144 1 - do source validation by reversed path, as specified in RFC1812
1145 Recommended option for single homed hosts and stub network
1146 routers. Could cause troubles for complicated (not loop free)
1147 networks running a slow unreliable protocol (sort of RIP),
1148 or using static routes.
1149 0 - No source validation.
1151 c = nvram_get("wan_ifname");
1152 /* mcast needs rp filter to be turned off only for non default iface */
1153 if (!(nvram_match("multicast_pass", "1")) || strcmp(wanface, c) == 0) c = NULL;
1155 if ((dir = opendir("/proc/sys/net/ipv4/conf")) != NULL) {
1156 while ((dirent = readdir(dir)) != NULL) {
1157 sprintf(s, "/proc/sys/net/ipv4/conf/%s/rp_filter", dirent->d_name);
1158 f_write_string(s, (c && strcmp(dirent->d_name, c) == 0) ? "0" : "1", 0, 0);
1160 closedir(dir);
1163 remotemanage = 0;
1164 gateway_mode = !nvram_match("wk_mode", "router");
1165 if (gateway_mode) {
1166 /* Remote management */
1167 if (nvram_match("remote_management", "1") && nvram_invmatch("http_wanport", "") &&
1168 nvram_invmatch("http_wanport", "0")) remotemanage = 1;
1171 if ((ipt_file = fopen(ipt_fname, "w")) == NULL) {
1172 notice_set("iptables", "Unable to create iptables restore file");
1173 simple_unlock("firewall");
1174 return 0;
1177 #ifdef TCONFIG_IPV6
1178 if ((ip6t_file = fopen(ip6t_fname, "w")) == NULL) {
1179 notice_set("ip6tables", "Unable to create ip6tables restore file");
1180 simple_unlock("firewall");
1181 return 0;
1183 modprobe("nf_conntrack_ipv6");
1184 modprobe("ip6t_REJECT");
1185 #endif
1187 mangle_table();
1188 nat_table();
1189 filter_table();
1191 fclose(ipt_file);
1192 ipt_file = NULL;
1194 #ifdef TCONFIG_IPV6
1195 fclose(ip6t_file);
1196 ip6t_file = NULL;
1197 #endif
1199 #ifdef DEBUG_IPTFILE
1200 if (debug_only) {
1201 simple_unlock("firewall");
1202 simple_unlock("restrictions");
1203 return 0;
1205 #endif
1207 save_webmon();
1209 if (nvram_get_int("upnp_enable") & 3) {
1210 f_write("/etc/upnp/save", NULL, 0, 0, 0);
1211 if (killall("miniupnpd", SIGUSR2) == 0) {
1212 f_wait_notexists("/etc/upnp/save", 5);
1216 notice_set("iptables", "");
1217 if (_eval(iptrestore_argv, ">/var/notice/iptables", 0, NULL) == 0) {
1218 led(LED_DIAG, 0);
1219 notice_set("iptables", "");
1221 else {
1222 sprintf(s, "%s.error", ipt_fname);
1223 rename(ipt_fname, s);
1224 syslog(LOG_CRIT, "Error while loading rules. See %s file.", s);
1225 led(LED_DIAG, 1);
1229 -P INPUT DROP
1230 -F INPUT
1231 -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
1232 -A INPUT -i br0 -j ACCEPT
1234 -P FORWARD DROP
1235 -F FORWARD
1236 -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
1237 -A FORWARD -i br0 -j ACCEPT
1242 #ifdef TCONFIG_IPV6
1243 if (ipv6_enabled()) {
1244 notice_set("ip6tables", "");
1245 if (_eval(ip6trestore_argv, ">/var/notice/ip6tables", 0, NULL) == 0) {
1246 led(LED_DIAG, 0);
1247 notice_set("ip6tables", "");
1249 else {
1250 sprintf(s, "%s.error", ip6t_fname);
1251 rename(ip6t_fname, s);
1252 syslog(LOG_CRIT, "Error while loading rules. See %s file.", s);
1253 led(LED_DIAG, 1);
1256 #endif
1258 if (nvram_get_int("upnp_enable") & 3) {
1259 f_write("/etc/upnp/load", NULL, 0, 0, 0);
1260 killall("miniupnpd", SIGUSR2);
1263 simple_unlock("restrictions");
1264 sched_restrictions();
1265 enable_ip_forward();
1267 led(LED_DMZ, dmz_dst(NULL));
1269 #ifdef TCONFIG_IPV6
1270 modprobe_r("nf_conntrack_ipv6");
1271 modprobe_r("ip6t_LOG");
1272 modprobe_r("ip6t_REJECT");
1273 #endif
1274 #ifdef LINUX26
1275 modprobe_r("xt_layer7");
1276 modprobe_r("xt_recent");
1277 modprobe_r("xt_HL");
1278 modprobe_r("xt_length");
1279 modprobe_r("xt_web");
1280 modprobe_r("xt_webmon");
1281 modprobe_r("xt_dscp");
1282 #else
1283 modprobe_r("ipt_layer7");
1284 modprobe_r("ipt_recent");
1285 modprobe_r("ipt_TTL");
1286 modprobe_r("ipt_web");
1287 modprobe_r("ipt_webmon");
1288 modprobe_r("ipt_dscp");
1289 #endif
1290 modprobe_r("ipt_ipp2p");
1292 unlink("/var/webmon/domain");
1293 unlink("/var/webmon/search");
1295 #ifdef TCONFIG_OPENVPN
1296 run_vpn_firewall_scripts();
1297 #endif
1298 run_nvscript("script_fire", NULL, 1);
1300 simple_unlock("firewall");
1301 return 0;
1304 int stop_firewall(void)
1306 led(LED_DMZ, 0);
1307 return 0;
1310 #ifdef DEBUG_IPTFILE
1311 void create_test_iptfile(void)
1313 debug_only = 1;
1314 start_firewall();
1315 debug_only = 0;
1317 #endif