Merge branch 'tomato-RT' into Toastman-RT
[tomato.git] / release / src / router / rc / firewall.c
blobcc37c2f263d978bdfce622afa6dc88527e83882b
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;
61 // RFC-4890, sec. 4.3.1
62 const int allowed_icmpv6[] = { 1, 2, 3, 4, 128, 129 };
63 #endif
67 struct {
68 } firewall_data;
71 // -----------------------------------------------------------------------------
74 void enable_ip_forward(void)
77 ip_forward - BOOLEAN
78 0 - disabled (default)
79 not 0 - enabled
81 Forward Packets between interfaces.
83 This variable is special, its change resets all configuration
84 parameters to their default state (RFC1122 for hosts, RFC1812
85 for routers)
87 f_write_string("/proc/sys/net/ipv4/ip_forward", "1", 0, 0);
89 #ifdef TCONFIG_IPV6
90 if (ipv6_enabled()) {
91 f_write_string("/proc/sys/net/ipv6/conf/default/forwarding", "1", 0, 0);
92 f_write_string("/proc/sys/net/ipv6/conf/all/forwarding", "1", 0, 0);
94 #endif
98 // -----------------------------------------------------------------------------
101 static int ip2cclass(char *ipaddr, char *new, int count)
103 int ip[4];
105 if (sscanf(ipaddr,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]) != 4) return 0;
106 return snprintf(new, count, "%d.%d.%d.",ip[0],ip[1],ip[2]);
111 static int dmz_dst(char *s)
113 struct in_addr ia;
114 char *p;
115 int n;
117 if (nvram_get_int("dmz_enable") <= 0) return 0;
119 p = nvram_safe_get("dmz_ipaddr");
120 if ((ia.s_addr = inet_addr(p)) == (in_addr_t)-1) {
121 if (((n = atoi(p)) <= 0) || (n >= 255)) return 0;
122 if (s) sprintf(s, "%s%d", lan_cclass, n);
123 return 1;
126 if (s) strcpy(s, inet_ntoa(ia));
127 return 1;
130 void ipt_log_unresolved(const char *addr, const char *addrtype, const char *categ, const char *name)
132 char *pre, *post;
134 pre = (name && *name) ? " for \"" : "";
135 post = (name && *name) ? "\"" : "";
137 syslog(LOG_WARNING, "firewall: "
138 "%s: not using %s%s%s%s (could not resolve as valid %s address)",
139 categ, addr, pre, (name) ? : "", post, (addrtype) ? : "IP");
142 int ipt_addr(char *addr, int maxlen, const char *s, const char *dir, int af,
143 int strict, const char *categ, const char *name)
145 char p[INET6_ADDRSTRLEN * 2];
146 int r = 0;
148 if ((s) && (*s) && (*dir))
150 if (sscanf(s, "%[0-9.]-%[0-9.]", p, p) == 2) {
151 snprintf(addr, maxlen, "-m iprange --%s-range %s", dir, s);
152 r = IPT_V4;
154 #ifdef TCONFIG_IPV6
155 else if (sscanf(s, "%[0-9A-Fa-f:]-%[0-9A-Fa-f:]", p, p) == 2) {
156 snprintf(addr, maxlen, "-m iprange --%s-range %s", dir, s);
157 r = IPT_V6;
159 #endif
160 else {
161 snprintf(addr, maxlen, "-%c %s", dir[0], s);
162 if (sscanf(s, "%[^/]/", p)) {
163 #ifdef TCONFIG_IPV6
164 r = host_addrtypes(p, strict ? af : (IPT_V4 | IPT_V6));
165 #else
166 r = host_addrtypes(p, IPT_V4);
167 #endif
171 else
173 *addr = 0;
174 r = (IPT_V4 | IPT_V6);
177 if ((r == 0 || (strict && ((r & af) != af))) && (categ && *categ)) {
178 ipt_log_unresolved(s, categ, name,
179 (af & IPT_V4 & ~r) ? "IPv4" : ((af & IPT_V6 & ~r) ? "IPv6" : NULL));
182 return (r & af);
185 #define ipt_source_strict(s, src, categ, name) ipt_addr(src, 64, s, "src", IPT_V4, 1, categ, name)
186 #define ipt_source(s, src, categ, name) ipt_addr(src, 64, s, "src", IPT_V4, 0, categ, name)
187 #define ip6t_source(s, src, categ, name) ipt_addr(src, 128, s, "src", IPT_V6, 0, categ, name)
190 static void get_src(const char *nv, char *src)
192 char *p;
194 if (((p = nvram_get(nv)) != NULL) && (*p) && (strlen(p) < 32)) {
195 sprintf(src, "-%s %s", strchr(p, '-') ? "m iprange --src-range" : "s", p);
197 else {
198 *src = 0;
203 void ipt_write(const char *format, ...)
205 va_list args;
207 va_start(args, format);
208 vfprintf(ipt_file, format, args);
209 va_end(args);
212 void ip6t_write(const char *format, ...)
214 #ifdef TCONFIG_IPV6
215 va_list args;
217 va_start(args, format);
218 vfprintf(ip6t_file, format, args);
219 va_end(args);
220 #endif
223 // -----------------------------------------------------------------------------
225 int ipt_dscp(const char *v, char *opt)
227 unsigned int n;
229 if (*v == 0) {
230 *opt = 0;
231 return 0;
234 n = strtoul(v, NULL, 0);
235 if (n > 63) n = 63;
236 sprintf(opt, " -m dscp --dscp 0x%02X", n);
238 #ifdef LINUX26
239 modprobe("xt_dscp");
240 #else
241 modprobe("ipt_dscp");
242 #endif
243 return 1;
246 // -----------------------------------------------------------------------------
249 int ipt_ipp2p(const char *v, char *opt)
251 int n = atoi(v);
253 if (n == 0) {
254 *opt = 0;
255 return 0;
258 strcpy(opt, "-m ipp2p ");
259 if ((n & 0xFFF) == 0xFFF) {
260 strcat(opt, "--ipp2p");
262 else {
263 // x12
264 if (n & 0x0001) strcat(opt, "--apple ");
265 if (n & 0x0002) strcat(opt, "--ares ");
266 if (n & 0x0004) strcat(opt, "--bit ");
267 if (n & 0x0008) strcat(opt, "--dc ");
268 if (n & 0x0010) strcat(opt, "--edk ");
269 if (n & 0x0020) strcat(opt, "--gnu ");
270 if (n & 0x0040) strcat(opt, "--kazaa ");
271 if (n & 0x0080) strcat(opt, "--mute ");
272 if (n & 0x0100) strcat(opt, "--soul ");
273 if (n & 0x0200) strcat(opt, "--waste ");
274 if (n & 0x0400) strcat(opt, "--winmx ");
275 if (n & 0x0800) strcat(opt, "--xdcc ");
278 modprobe("ipt_ipp2p");
279 return 1;
283 // -----------------------------------------------------------------------------
286 char **layer7_in;
288 // This L7 matches inbound traffic, caches the results, then the L7 outbound
289 // should read the cached result and set the appropriate marks -- zzz
290 void ipt_layer7_inbound(void)
292 int en, i;
293 char **p;
295 if (!layer7_in) return;
297 en = nvram_match("nf_l7in", "1");
298 if (en) {
299 ipt_write(":L7in - [0:0]\n");
300 for (i = 0; i < wanfaces.count; ++i) {
301 if (*(wanfaces.iface[i].name)) {
302 ipt_write("-A FORWARD -i %s -j L7in\n",
303 wanfaces.iface[i].name);
308 p = layer7_in;
309 while (*p) {
310 if (en) ipt_write("-A L7in %s -j RETURN\n", *p);
311 free(*p);
312 ++p;
314 free(layer7_in);
315 layer7_in = NULL;
318 int ipt_layer7(const char *v, char *opt)
320 char s[128];
321 char *path;
323 *opt = 0;
324 if (*v == 0) return 0;
325 if (strlen(v) > 32) return -1;
327 path = "/etc/l7-extra";
328 sprintf(s, "%s/%s.pat", path, v);
329 if (!f_exists(s)) {
330 path = "/etc/l7-protocols";
331 sprintf(s, "%s/%s.pat", path, v);
332 if (!f_exists(s)) {
333 syslog(LOG_ERR, "L7 %s was not found", v);
334 return -1;
338 sprintf(opt, "-m layer7 --l7dir %s --l7proto %s", path, v);
340 if (nvram_match("nf_l7in", "1")) {
341 if (!layer7_in) layer7_in = calloc(51, sizeof(char *));
342 if (layer7_in) {
343 char **p;
345 p = layer7_in;
346 while (*p) {
347 if (strcmp(*p, opt) == 0) return 1;
348 ++p;
350 if (((p - layer7_in) / sizeof(char *)) < 50) *p = strdup(opt);
354 #ifdef LINUX26
355 modprobe("xt_layer7");
356 #else
357 modprobe("ipt_layer7");
358 #endif
359 return 1;
363 // -----------------------------------------------------------------------------
365 static void save_webmon(void)
367 eval("cp", "/proc/webmon_recent_domains", "/var/webmon/domain");
368 eval("cp", "/proc/webmon_recent_searches", "/var/webmon/search");
371 static void ipt_webmon()
373 int wmtype, clear, i;
374 char t[512];
375 char src[128];
376 char *p, *c;
377 int ok;
379 if (!nvram_get_int("log_wm")) return;
380 wmtype = nvram_get_int("log_wmtype");
381 clear = nvram_get_int("log_wmclear");
383 ip46t_write(":monitor - [0:0]\n");
385 // include IPs
386 strlcpy(t, wmtype == 1 ? nvram_safe_get("log_wmip") : "", sizeof(t));
387 p = t;
388 do {
389 if ((c = strchr(p, ',')) != NULL) *c = 0;
391 if ((ok = ipt_addr(src, sizeof(src), p, "src", IPT_V4|IPT_V6, 0, "webmon", NULL))) {
392 #ifdef TCONFIG_IPV6
393 if (*wan6face && (ok & IPT_V6))
394 ip6t_write("-A FORWARD -o %s %s -j monitor\n", wan6face, src);
395 #endif
396 if (ok & IPT_V4) {
397 for (i = 0; i < wanfaces.count; ++i) {
398 if (*(wanfaces.iface[i].name)) {
399 ipt_write("-A FORWARD -o %s %s -j monitor\n",
400 wanfaces.iface[i].name, src);
406 if (!c) break;
407 p = c + 1;
408 } while (*p);
410 // exclude IPs
411 if (wmtype == 2) {
412 strlcpy(t, nvram_safe_get("log_wmip"), sizeof(t));
413 p = t;
414 do {
415 if ((c = strchr(p, ',')) != NULL) *c = 0;
416 if ((ok = ipt_addr(src, sizeof(src), p, "src", IPT_V4|IPT_V6, 0, "webmon", NULL))) {
417 if (*src)
418 ip46t_flagged_write(ok, "-A monitor %s -j RETURN\n", src);
420 if (!c) break;
421 p = c + 1;
422 } while (*p);
425 ip46t_write(
426 "-A monitor -p tcp -m webmon "
427 "--max_domains %d --max_searches %d %s %s -j RETURN\n",
428 nvram_get_int("log_wmdmax") ? : 1, nvram_get_int("log_wmsmax") ? : 1,
429 (clear & 1) == 0 ? "--domain_load_file /var/webmon/domain" : "--clear_domain",
430 (clear & 2) == 0 ? "--search_load_file /var/webmon/search" : "--clear_search");
432 #ifdef LINUX26
433 modprobe("xt_webmon");
434 #else
435 modprobe("ipt_webmon");
436 #endif
440 // -----------------------------------------------------------------------------
441 // MANGLE
442 // -----------------------------------------------------------------------------
444 static void mangle_table(void)
446 int ttl;
447 char *p, *wanface;
449 ip46t_write(
450 "*mangle\n"
451 ":PREROUTING ACCEPT [0:0]\n"
452 ":OUTPUT ACCEPT [0:0]\n");
454 if (wanup) {
456 ipt_qos();
457 //1 for mangle
458 ipt_qoslimit(1);
460 p = nvram_safe_get("nf_ttl");
461 if (strncmp(p, "c:", 2) == 0) {
462 p += 2;
463 ttl = atoi(p);
464 p = (ttl >= 0 && ttl <= 255) ? "set" : NULL;
466 else if ((ttl = atoi(p)) != 0) {
467 if (ttl > 0) {
468 p = "inc";
470 else {
471 ttl = -ttl;
472 p = "dec";
474 if (ttl > 255) p = NULL;
476 else p = NULL;
478 if (p) {
479 #ifdef LINUX26
480 modprobe("xt_HL");
481 #else
482 modprobe("ipt_TTL");
483 #endif
484 // set TTL on primary WAN iface only
485 wanface = wanfaces.iface[0].name;
486 ip46t_write(
487 "-I PREROUTING -i %s -j TTL --ttl-%s %d\n"
488 "-I POSTROUTING -o %s -j TTL --ttl-%s %d\n",
489 wanface, p, ttl,
490 wanface, p, ttl);
494 ip46t_write("COMMIT\n");
497 // -----------------------------------------------------------------------------
498 // NAT
499 // -----------------------------------------------------------------------------
501 static void nat_table(void)
503 char lanaddr[32];
504 char lanmask[32];
505 char dst[64];
506 char src[64];
507 char t[512];
508 char *p, *c;
509 int i;
511 ipt_write("*nat\n"
512 ":PREROUTING ACCEPT [0:0]\n"
513 ":POSTROUTING ACCEPT [0:0]\n"
514 ":OUTPUT ACCEPT [0:0]\n"
515 ":%s - [0:0]\n",
516 chain_wan_prerouting);
518 //2 for nat
519 ipt_qoslimit(2);
521 if (gateway_mode) {
522 strlcpy(lanaddr, nvram_safe_get("lan_ipaddr"), sizeof(lanaddr));
523 strlcpy(lanmask, nvram_safe_get("lan_netmask"), sizeof(lanmask));
525 for (i = 0; i < wanfaces.count; ++i) {
526 if (*(wanfaces.iface[i].name)) {
527 // Drop incoming packets which destination IP address is to our LAN side directly
528 ipt_write("-A PREROUTING -i %s -d %s/%s -j DROP\n",
529 wanfaces.iface[i].name,
530 lanaddr, lanmask); // note: ipt will correct lanaddr
532 // chain_wan_prerouting
533 if (wanup) {
534 ipt_write("-A PREROUTING -d %s -j %s\n",
535 wanfaces.iface[i].ip, chain_wan_prerouting);
540 if (wanup) {
541 if (nvram_match("dns_intcpt", "1")) {
542 ipt_write("-A PREROUTING -p udp -s %s/%s ! -d %s/%s --dport 53 -j DNAT --to-destination %s\n",
543 lanaddr, lanmask,
544 lanaddr, lanmask,
545 lanaddr);
548 // ICMP packets are always redirected to INPUT chains
549 ipt_write("-A %s -p icmp -j DNAT --to-destination %s\n", chain_wan_prerouting, lanaddr);
551 ipt_forward(IPT_TABLE_NAT);
552 ipt_triggered(IPT_TABLE_NAT);
555 if (nvram_get_int("upnp_enable") & 3) {
556 ipt_write(":upnp - [0:0]\n");
558 for (i = 0; i < wanfaces.count; ++i) {
559 if (*(wanfaces.iface[i].name)) {
560 if (wanup) {
561 // ! for loopback (all) to work
562 ipt_write("-A PREROUTING -d %s -j upnp\n", wanfaces.iface[i].ip);
564 else {
565 ipt_write("-A PREROUTING -i %s -j upnp\n", wanfaces.iface[i].name);
571 if (wanup) {
572 if (dmz_dst(dst)) {
573 strlcpy(t, nvram_safe_get("dmz_sip"), sizeof(t));
574 p = t;
575 do {
576 if ((c = strchr(p, ',')) != NULL) *c = 0;
577 if (ipt_source_strict(p, src, "dmz", NULL))
578 ipt_write("-A %s %s -j DNAT --to-destination %s\n", chain_wan_prerouting, src, dst);
579 if (!c) break;
580 p = c + 1;
581 } while (*p);
585 p = "";
586 #ifdef TCONFIG_IPV6
587 switch (get_ipv6_service()) {
588 case IPV6_6IN4:
589 // avoid NATing proto-41 packets when using 6in4 tunnel
590 p = "-p ! 41";
591 break;
593 #endif
595 for (i = 0; i < wanfaces.count; ++i) {
596 if (*(wanfaces.iface[i].name)) {
597 if ((!wanup) || (nvram_get_int("net_snat") != 1))
598 ipt_write("-A POSTROUTING %s -o %s -j MASQUERADE\n", p, wanfaces.iface[i].name);
599 else
600 ipt_write("-A POSTROUTING %s -o %s -j SNAT --to-source %s\n", p, wanfaces.iface[i].name, wanfaces.iface[i].ip);
604 switch (nvram_get_int("nf_loopback")) {
605 case 1: // 1 = forwarded-only
606 case 2: // 2 = disable
607 break;
608 default: // 0 = all (same as block_loopback=0)
609 ipt_write("-A POSTROUTING -o %s -s %s/%s -d %s/%s -j SNAT --to-source %s\n",
610 lanface,
611 lanaddr, lanmask,
612 lanaddr, lanmask,
613 lanaddr);
614 break;
617 ipt_write("COMMIT\n");
620 // -----------------------------------------------------------------------------
621 // FILTER
622 // -----------------------------------------------------------------------------
624 static void filter_input(void)
626 char s[64];
627 char t[512];
628 char *en;
629 char *sec;
630 char *hit;
631 int n;
632 char *p, *c;
634 if ((nvram_get_int("nf_loopback") != 0) && (wanup)) { // 0 = all
635 for (n = 0; n < wanfaces.count; ++n) {
636 if (*(wanfaces.iface[n].name)) {
637 ipt_write("-A INPUT -i %s -d %s -j DROP\n", lanface, wanfaces.iface[n].ip);
642 ipt_write(
643 "-A INPUT -m state --state INVALID -j DROP\n"
644 "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n");
646 strlcpy(s, nvram_safe_get("ne_shlimit"), sizeof(s));
647 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && ((n = atoi(en) & 3) != 0)) {
649 ? what if the user uses the start button in GUI ?
650 if (nvram_get_int("telnetd_eas"))
651 if (nvram_get_int("sshd_eas"))
653 #ifdef LINUX26
654 modprobe("xt_recent");
655 #else
656 modprobe("ipt_recent");
657 #endif
659 ipt_write(
660 "-N shlimit\n"
661 "-A shlimit -m recent --set --name shlimit\n"
662 "-A shlimit -m recent --update --hitcount %d --seconds %s --name shlimit -j %s\n",
663 atoi(hit) + 1, sec, chain_in_drop);
665 if (n & 1) {
666 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_port"));
667 if (nvram_get_int("sshd_remote") && nvram_invmatch("sshd_rport", nvram_safe_get("sshd_port"))) {
668 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_rport"));
671 if (n & 2) ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("telnetd_port"));
674 #ifdef TCONFIG_FTP
675 strlcpy(s, nvram_safe_get("ftp_limit"), sizeof(s));
676 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && (atoi(en)) && (nvram_get_int("ftp_enable") == 1)) {
677 #ifdef LINUX26
678 modprobe("xt_recent");
679 #else
680 modprobe("ipt_recent");
681 #endif
683 ipt_write(
684 "-N ftplimit\n"
685 "-A ftplimit -m recent --set --name ftp\n"
686 "-A ftplimit -m recent --update --hitcount %d --seconds %s --name ftp -j %s\n",
687 atoi(hit) + 1, sec, chain_in_drop);
688 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j ftplimit\n", nvram_safe_get("ftp_port"));
690 #endif
692 ipt_write(
693 "-A INPUT -i %s -j ACCEPT\n"
694 "-A INPUT -i lo -j ACCEPT\n",
695 lanface);
697 #ifdef TCONFIG_IPV6
698 switch (get_ipv6_service()) {
699 case IPV6_6IN4:
700 // Accept ICMP requests from the remote tunnel endpoint
701 if ((p = nvram_get("ipv6_tun_v4end")) && *p && strcmp(p, "0.0.0.0") != 0)
702 ipt_write("-A INPUT -p icmp -s %s -j %s\n", p, chain_in_accept);
703 ipt_write("-A INPUT -p 41 -j %s\n", chain_in_accept);
704 break;
706 #endif
708 // ICMP request from WAN interface
709 if (nvram_match("block_wan", "0")) {
710 // allow ICMP packets to be received, but restrict the flow to avoid ping flood attacks
711 ipt_write("-A INPUT -p icmp -m limit --limit 1/second -j %s\n", chain_in_accept);
712 // allow udp traceroute packets
713 ipt_write("-A INPUT -p udp -m udp --dport 33434:33534 -m limit --limit 5/second -j %s\n", chain_in_accept);
716 /* Accept incoming packets from broken dhcp servers, which are sending replies
717 * from addresses other than used for query. This could lead to a lower level
718 * of security, so allow to disable it via nvram variable.
720 if (nvram_invmatch("dhcp_pass", "0") && using_dhcpc()) {
721 ipt_write("-A INPUT -p udp --sport 67 --dport 68 -j %s\n", chain_in_accept);
724 strlcpy(t, nvram_safe_get("rmgt_sip"), sizeof(t));
725 p = t;
726 do {
727 if ((c = strchr(p, ',')) != NULL) *c = 0;
729 if (ipt_source(p, s, "remote management", NULL)) {
731 if (remotemanage) {
732 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
733 s, nvram_safe_get("http_wanport"), chain_in_accept);
736 if (nvram_get_int("sshd_remote")) {
737 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
738 s, nvram_safe_get("sshd_rport"), chain_in_accept);
742 if (!c) break;
743 p = c + 1;
744 } while (*p);
746 #ifdef TCONFIG_FTP // !!TB - FTP Server
747 if (nvram_match("ftp_enable", "1")) { // FTP WAN access enabled
748 strlcpy(t, nvram_safe_get("ftp_sip"), sizeof(t));
749 p = t;
750 do {
751 if ((c = strchr(p, ',')) != NULL) *c = 0;
752 if (ipt_source(p, s, "ftp", "remote access")) {
753 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
754 s, nvram_safe_get("ftp_port"), chain_in_accept);
756 if (!c) break;
757 p = c + 1;
758 } while (*p);
760 #endif
762 // IGMP query from WAN interface
763 if (nvram_match("multicast_pass", "1")) {
764 ipt_write("-A INPUT -p igmp -d 224.0.0.0/4 -j ACCEPT\n");
765 ipt_write("-A INPUT -p udp -d 224.0.0.0/4 ! --dport 1900 -j ACCEPT\n");
768 // Routing protocol, RIP, accept
769 if (nvram_invmatch("dr_wan_rx", "0")) {
770 ipt_write("-A INPUT -p udp -m udp --dport 520 -j ACCEPT\n");
773 // if logging
774 if (*chain_in_drop == 'l') {
775 ipt_write( "-A INPUT -j %s\n", chain_in_drop);
778 // default policy: DROP
781 // clamp TCP MSS to PMTU of WAN interface (IPv4 only?)
782 static void clampmss(void)
784 #if 1
785 ipt_write("-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu\n");
786 #else
787 int rmtu = nvram_get_int("wan_run_mtu");
788 ipt_write("-A FORWARD -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss %d: -j TCPMSS ", rmtu - 39);
789 if (rmtu < 576) {
790 ipt_write("--clamp-mss-to-pmtu\n");
792 else {
793 ipt_write("--set-mss %d\n", rmtu - 40);
795 #endif
798 static void filter_forward(void)
800 char dst[64];
801 char src[64];
802 char t[512];
803 char *p, *c;
804 int i;
806 #ifdef TCONFIG_IPV6
807 ip6t_write(
808 "-A FORWARD -m rt --rt-type 0 -j DROP\n");
809 #endif
811 ip46t_write(
812 "-A FORWARD -i %s -o %s -j ACCEPT\n", // accept all lan to lan
813 lanface, lanface);
815 // IPv4 only ?
816 ipt_write(
817 "-A FORWARD -m state --state INVALID -j DROP\n"); // drop if INVALID state
819 // clamp tcp mss to pmtu
820 clampmss();
822 if (wanup) {
823 ipt_restrictions();
825 ipt_layer7_inbound();
828 ipt_webmon();
830 ip46t_write(
831 ":wanin - [0:0]\n"
832 ":wanout - [0:0]\n"
833 "-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT\n"); // already established or related (via helper)
835 #ifdef TCONFIG_IPV6
836 // Filter out invalid WAN->WAN connections
837 if (*wan6face)
838 ip6t_write("-A FORWARD -o %s ! -i %s -j %s\n", wan6face, lanface, chain_in_drop);
840 #ifdef LINUX26
841 modprobe("xt_length");
842 ip6t_write("-A FORWARD -p ipv6-nonxt -m length --length 40 -j ACCEPT\n");
843 #endif
845 // ICMPv6 rules
846 for (i = 0; i < sizeof(allowed_icmpv6)/sizeof(int); ++i) {
847 ip6t_write("-A FORWARD -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_icmpv6[i], chain_in_accept);
850 if (*wan6face) {
851 ip6t_write(
852 "-A FORWARD -i %s -j wanin\n" // generic from wan
853 "-A FORWARD -o %s -j wanout\n", // generic to wan
854 wan6face, wan6face);
856 #endif
858 for (i = 0; i < wanfaces.count; ++i) {
859 if (*(wanfaces.iface[i].name)) {
860 ipt_write(
861 "-A FORWARD -i %s -j wanin\n" // generic from wan
862 "-A FORWARD -o %s -j wanout\n", // generic to wan
863 wanfaces.iface[i].name, wanfaces.iface[i].name);
867 ip46t_write("-A FORWARD -i %s -j %s\n", // from lan
868 lanface, chain_out_accept);
870 // IPv4 only
871 if (nvram_get_int("upnp_enable") & 3) {
872 ipt_write(":upnp - [0:0]\n");
873 for (i = 0; i < wanfaces.count; ++i) {
874 if (*(wanfaces.iface[i].name)) {
875 ipt_write("-A FORWARD -i %s -j upnp\n",
876 wanfaces.iface[i].name);
881 if (wanup) {
882 if (nvram_match("multicast_pass", "1")) {
883 ipt_write("-A wanin -p udp -d 224.0.0.0/4 -j %s\n", chain_in_accept);
885 ipt_triggered(IPT_TABLE_FILTER);
886 ipt_forward(IPT_TABLE_FILTER);
887 #ifdef TCONFIG_IPV6
888 ip6t_forward();
889 #endif
891 if (dmz_dst(dst)) {
892 strlcpy(t, nvram_safe_get("dmz_sip"), sizeof(t));
893 p = t;
894 do {
895 if ((c = strchr(p, ',')) != NULL) *c = 0;
896 if (ipt_source_strict(p, src, "dmz", NULL))
897 ipt_write("-A FORWARD -o %s %s -d %s -j %s\n", lanface, src, dst, chain_in_accept);
898 if (!c) break;
899 p = c + 1;
900 } while (*p);
904 // default policy: DROP
907 static void filter_log(void)
909 int n;
910 char limit[128];
912 n = nvram_get_int("log_limit");
913 if ((n >= 1) && (n <= 9999)) {
914 sprintf(limit, "-m limit --limit %d/m", n);
916 else {
917 limit[0] = 0;
920 #ifdef TCONFIG_IPV6
921 modprobe("ip6t_LOG");
922 #endif
923 if ((*chain_in_drop == 'l') || (*chain_out_drop == 'l')) {
924 ip46t_write(
925 ":logdrop - [0:0]\n"
926 "-A logdrop -m state --state NEW %s -j LOG --log-prefix \"DROP \""
927 #ifdef LINUX26
928 " --log-macdecode"
929 #endif
930 " --log-tcp-sequence --log-tcp-options --log-ip-options\n"
931 "-A logdrop -j DROP\n"
932 ":logreject - [0:0]\n"
933 "-A logreject %s -j LOG --log-prefix \"REJECT \""
934 #ifdef LINUX26
935 " --log-macdecode"
936 #endif
937 " --log-tcp-sequence --log-tcp-options --log-ip-options\n"
938 "-A logreject -p tcp -j REJECT --reject-with tcp-reset\n",
939 limit, limit);
941 if ((*chain_in_accept == 'l') || (*chain_out_accept == 'l')) {
942 ip46t_write(
943 ":logaccept - [0:0]\n"
944 "-A logaccept -m state --state NEW %s -j LOG --log-prefix \"ACCEPT \""
945 #ifdef LINUX26
946 " --log-macdecode"
947 #endif
948 " --log-tcp-sequence --log-tcp-options --log-ip-options\n"
949 "-A logaccept -j ACCEPT\n",
950 limit);
954 #ifdef TCONFIG_IPV6
955 static void filter6_input(void)
957 char s[128];
958 char t[512];
959 char *en;
960 char *sec;
961 char *hit;
962 int n;
963 char *p, *c;
965 // RFC-4890, sec. 4.4.1
966 const int allowed_local_icmpv6[] =
967 { 130, 131, 132, 133, 134, 135, 136,
968 141, 142, 143,
969 148, 149, 151, 152, 153 };
971 ip6t_write(
972 "-A INPUT -m rt --rt-type 0 -j %s\n"
973 /* "-A INPUT -m state --state INVALID -j DROP\n" */
974 "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n",
975 chain_in_drop);
977 #ifdef LINUX26
978 modprobe("xt_length");
979 ip6t_write("-A INPUT -p ipv6-nonxt -m length --length 40 -j ACCEPT\n");
980 #endif
982 strlcpy(s, nvram_safe_get("ne_shlimit"), sizeof(s));
983 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && ((n = atoi(en) & 3) != 0)) {
984 #ifdef LINUX26
985 modprobe("xt_recent");
986 #else
987 modprobe("ipt_recent");
988 #endif
990 ip6t_write(
991 "-N shlimit\n"
992 "-A shlimit -m recent --set --name shlimit\n"
993 "-A shlimit -m recent --update --hitcount %d --seconds %s --name shlimit -j %s\n",
994 atoi(hit) + 1, sec, chain_in_drop);
996 if (n & 1) {
997 ip6t_write("-A INPUT -i %s -p tcp --dport %s -m state --state NEW -j shlimit\n", lanface, nvram_safe_get("sshd_port"));
998 if (nvram_get_int("sshd_remote") && nvram_invmatch("sshd_rport", nvram_safe_get("sshd_port"))) {
999 ip6t_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_rport"));
1002 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"));
1005 #ifdef TCONFIG_FTP
1006 strlcpy(s, nvram_safe_get("ftp_limit"), sizeof(s));
1007 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && (atoi(en)) && (nvram_get_int("ftp_enable") == 1)) {
1008 #ifdef LINUX26
1009 modprobe("xt_recent");
1010 #else
1011 modprobe("ipt_recent");
1012 #endif
1014 ip6t_write(
1015 "-N ftplimit\n"
1016 "-A ftplimit -m recent --set --name ftp\n"
1017 "-A ftplimit -m recent --update --hitcount %d --seconds %s --name ftp -j %s\n",
1018 atoi(hit) + 1, sec, chain_in_drop);
1019 ip6t_write("-A INPUT -p tcp --dport %s -m state --state NEW -j ftplimit\n", nvram_safe_get("ftp_port"));
1021 #endif // TCONFIG_FTP
1023 ip6t_write(
1024 "-A INPUT -i %s -j ACCEPT\n" // anything coming from LAN
1025 "-A INPUT -i lo -j ACCEPT\n",
1026 lanface );
1028 switch (get_ipv6_service()) {
1029 case IPV6_NATIVE_DHCP:
1030 // allow responses from the dhcpv6 server
1031 ip6t_write("-A INPUT -p udp --dport 546 -j %s\n", chain_in_accept);
1032 break;
1035 // ICMPv6 rules
1036 for (n = 0; n < sizeof(allowed_icmpv6)/sizeof(int); n++) {
1037 ip6t_write("-A INPUT -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_icmpv6[n], chain_in_accept);
1039 for (n = 0; n < sizeof(allowed_local_icmpv6)/sizeof(int); n++) {
1040 ip6t_write("-A INPUT -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_local_icmpv6[n], chain_in_accept);
1043 // Remote Managment
1044 strlcpy(t, nvram_safe_get("rmgt_sip"), sizeof(t));
1045 p = t;
1046 do {
1047 if ((c = strchr(p, ',')) != NULL) *c = 0;
1049 if (ip6t_source(p, s, "remote management", NULL)) {
1051 if (remotemanage) {
1052 ip6t_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
1053 s, nvram_safe_get("http_wanport"), chain_in_accept);
1056 if (nvram_get_int("sshd_remote")) {
1057 ip6t_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
1058 s, nvram_safe_get("sshd_rport"), chain_in_accept);
1062 if (!c) break;
1063 p = c + 1;
1064 } while (*p);
1066 #ifdef TCONFIG_FTP
1067 // FTP server
1068 if (nvram_match("ftp_enable", "1")) { // FTP WAN access enabled
1069 strlcpy(t, nvram_safe_get("ftp_sip"), sizeof(t));
1070 p = t;
1071 do {
1072 if ((c = strchr(p, ',')) != NULL) *c = 0;
1073 if (ip6t_source(p, s, "ftp", "remote access")) {
1074 ip6t_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
1075 s, nvram_safe_get("ftp_port"), chain_in_accept);
1077 if (!c) break;
1078 p = c + 1;
1079 } while (*p);
1081 #endif
1083 // if logging
1084 if (*chain_in_drop == 'l') {
1085 ip6t_write( "-A INPUT -j %s\n", chain_in_drop);
1088 // default policy: DROP
1091 #endif
1093 static void filter_table(void)
1095 ip46t_write(
1096 "*filter\n"
1097 ":INPUT DROP [0:0]\n"
1098 ":OUTPUT ACCEPT [0:0]\n"
1101 filter_log();
1103 filter_input();
1104 #ifdef TCONFIG_IPV6
1105 filter6_input();
1106 ip6t_write("-A OUTPUT -m rt --rt-type 0 -j %s\n", chain_in_drop);
1107 #endif
1109 if ((gateway_mode) || (nvram_match("wk_mode_x", "1"))) {
1110 ip46t_write(":FORWARD DROP [0:0]\n");
1111 filter_forward();
1113 else {
1114 ip46t_write(":FORWARD ACCEPT [0:0]\n");
1115 clampmss();
1117 ip46t_write("COMMIT\n");
1121 // -----------------------------------------------------------------------------
1123 int start_firewall(void)
1125 DIR *dir;
1126 struct dirent *dirent;
1127 char s[256];
1128 char *c, *wanface;
1129 int n;
1130 int wanproto;
1131 char *iptrestore_argv[] = { "iptables-restore", (char *)ipt_fname, NULL };
1132 #ifdef TCONFIG_IPV6
1133 char *ip6trestore_argv[] = { "ip6tables-restore", (char *)ip6t_fname, NULL };
1134 #endif
1136 simple_lock("firewall");
1137 simple_lock("restrictions");
1139 wanup = check_wanup();
1141 f_write_string("/proc/sys/net/ipv4/tcp_syncookies", nvram_get_int("ne_syncookies") ? "1" : "0", 0, 0);
1143 /* NAT performance tweaks
1144 * These values can be overriden later if needed via firewall script
1146 f_write_string("/proc/sys/net/core/netdev_max_backlog", "3072", 0, 0);
1147 f_write_string("/proc/sys/net/core/somaxconn", "3072", 0, 0);
1148 f_write_string("/proc/sys/net/ipv4/tcp_max_syn_backlog", "8192", 0, 0);
1149 f_write_string("/proc/sys/net/ipv4/tcp_fin_timeout", "30", 0, 0);
1150 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_intvl", "24", 0, 0);
1151 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_probes", "3", 0, 0);
1152 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_time", "1800", 0, 0);
1153 f_write_string("/proc/sys/net/ipv4/tcp_retries2", "5", 0, 0);
1154 f_write_string("/proc/sys/net/ipv4/tcp_syn_retries", "3", 0, 0);
1155 f_write_string("/proc/sys/net/ipv4/tcp_synack_retries", "3", 0, 0);
1156 f_write_string("/proc/sys/net/ipv4/tcp_tw_recycle", "1", 0, 0);
1157 f_write_string("/proc/sys/net/ipv4/tcp_tw_reuse", "1", 0, 0);
1159 /* DoS-related tweaks */
1160 f_write_string("/proc/sys/net/ipv4/icmp_ignore_bogus_error_responses", "1", 0, 0);
1161 f_write_string("/proc/sys/net/ipv4/tcp_rfc1337", "1", 0, 0);
1162 f_write_string("/proc/sys/net/ipv4/ip_local_port_range", "1024 65535", 0, 0);
1164 wanproto = get_wan_proto();
1165 f_write_string("/proc/sys/net/ipv4/ip_dynaddr", (wanproto == WP_DISABLED || wanproto == WP_STATIC) ? "0" : "1", 0, 0);
1167 #ifdef TCONFIG_EMF
1168 /* Force IGMPv2 due EMF limitations */
1169 if (nvram_get_int("emf_enable")) {
1170 f_write_string("/proc/sys/net/ipv4/conf/default/force_igmp_version", "2", 0, 0);
1171 f_write_string("/proc/sys/net/ipv4/conf/all/force_igmp_version", "2", 0, 0);
1173 #endif
1175 n = nvram_get_int("log_in");
1176 chain_in_drop = (n & 1) ? "logdrop" : "DROP";
1177 chain_in_accept = (n & 2) ? "logaccept" : "ACCEPT";
1179 n = nvram_get_int("log_out");
1180 chain_out_drop = (n & 1) ? "logdrop" : "DROP";
1181 chain_out_reject = (n & 1) ? "logreject" : "REJECT --reject-with tcp-reset";
1182 chain_out_accept = (n & 2) ? "logaccept" : "ACCEPT";
1184 // if (nvram_match("nf_drop_reset", "1")) chain_out_drop = chain_out_reject;
1186 strlcpy(lanface, nvram_safe_get("lan_ifname"), IFNAMSIZ);
1188 memcpy(&wanfaces, get_wanfaces(), sizeof(wanfaces));
1189 wanface = wanfaces.iface[0].name;
1190 #ifdef TCONFIG_IPV6
1191 strlcpy(wan6face, get_wan6face(), sizeof(wan6face));
1192 #endif
1194 strlcpy(s, nvram_safe_get("lan_ipaddr"), sizeof(s));
1195 if ((c = strrchr(s, '.')) != NULL) *(c + 1) = 0;
1196 strlcpy(lan_cclass, s, sizeof(lan_cclass));
1199 block obviously spoofed IP addresses
1201 rp_filter - BOOLEAN
1202 1 - do source validation by reversed path, as specified in RFC1812
1203 Recommended option for single homed hosts and stub network
1204 routers. Could cause troubles for complicated (not loop free)
1205 networks running a slow unreliable protocol (sort of RIP),
1206 or using static routes.
1207 0 - No source validation.
1209 c = nvram_get("wan_ifname");
1210 /* mcast needs rp filter to be turned off only for non default iface */
1211 if (!(nvram_match("multicast_pass", "1")) || strcmp(wanface, c) == 0) c = NULL;
1213 if ((dir = opendir("/proc/sys/net/ipv4/conf")) != NULL) {
1214 while ((dirent = readdir(dir)) != NULL) {
1215 sprintf(s, "/proc/sys/net/ipv4/conf/%s/rp_filter", dirent->d_name);
1216 f_write_string(s, (c && strcmp(dirent->d_name, c) == 0) ? "0" : "1", 0, 0);
1218 closedir(dir);
1221 remotemanage = 0;
1222 gateway_mode = !nvram_match("wk_mode", "router");
1223 if (gateway_mode) {
1224 /* Remote management */
1225 if (nvram_match("remote_management", "1") && nvram_invmatch("http_wanport", "") &&
1226 nvram_invmatch("http_wanport", "0")) remotemanage = 1;
1229 if ((ipt_file = fopen(ipt_fname, "w")) == NULL) {
1230 notice_set("iptables", "Unable to create iptables restore file");
1231 simple_unlock("firewall");
1232 return 0;
1235 #ifdef TCONFIG_IPV6
1236 if ((ip6t_file = fopen(ip6t_fname, "w")) == NULL) {
1237 notice_set("ip6tables", "Unable to create ip6tables restore file");
1238 simple_unlock("firewall");
1239 return 0;
1241 modprobe("nf_conntrack_ipv6");
1242 modprobe("ip6t_REJECT");
1243 #endif
1244 /*Deon Thomas attempt to start xt_IMQ and imq */
1245 /*shibby - fix modprobing IMQ for kernel 2.4 */
1246 modprobe("imq");
1247 #ifdef LINUX26
1248 modprobe("xt_IMQ");
1249 #else
1250 modprobe("ipt_IMQ");
1251 #endif
1253 mangle_table();
1254 nat_table();
1255 filter_table();
1257 fclose(ipt_file);
1258 ipt_file = NULL;
1260 #ifdef TCONFIG_IPV6
1261 fclose(ip6t_file);
1262 ip6t_file = NULL;
1263 #endif
1265 #ifdef DEBUG_IPTFILE
1266 if (debug_only) {
1267 simple_unlock("firewall");
1268 simple_unlock("restrictions");
1269 return 0;
1271 #endif
1273 save_webmon();
1275 if (nvram_get_int("upnp_enable") & 3) {
1276 f_write("/etc/upnp/save", NULL, 0, 0, 0);
1277 if (killall("miniupnpd", SIGUSR2) == 0) {
1278 f_wait_notexists("/etc/upnp/save", 5);
1282 notice_set("iptables", "");
1283 if (_eval(iptrestore_argv, ">/var/notice/iptables", 0, NULL) == 0) {
1284 led(LED_DIAG, 0);
1285 notice_set("iptables", "");
1287 else {
1288 sprintf(s, "%s.error", ipt_fname);
1289 rename(ipt_fname, s);
1290 syslog(LOG_CRIT, "Error while loading rules. See %s file.", s);
1291 led(LED_DIAG, 1);
1295 -P INPUT DROP
1296 -F INPUT
1297 -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
1298 -A INPUT -i br0 -j ACCEPT
1300 -P FORWARD DROP
1301 -F FORWARD
1302 -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
1303 -A FORWARD -i br0 -j ACCEPT
1308 #ifdef TCONFIG_IPV6
1309 if (ipv6_enabled()) {
1310 notice_set("ip6tables", "");
1311 if (_eval(ip6trestore_argv, ">/var/notice/ip6tables", 0, NULL) == 0) {
1312 notice_set("ip6tables", "");
1314 else {
1315 sprintf(s, "%s.error", ip6t_fname);
1316 rename(ip6t_fname, s);
1317 syslog(LOG_CRIT, "Error while loading rules. See %s file.", s);
1318 led(LED_DIAG, 1);
1321 else {
1322 eval("ip6tables", "-F");
1323 eval("ip6tables", "-t", "mangle", "-F");
1325 #endif
1327 if (nvram_get_int("upnp_enable") & 3) {
1328 f_write("/etc/upnp/load", NULL, 0, 0, 0);
1329 killall("miniupnpd", SIGUSR2);
1332 simple_unlock("restrictions");
1333 sched_restrictions();
1334 enable_ip_forward();
1336 led(LED_DMZ, dmz_dst(NULL));
1338 #ifdef TCONFIG_IPV6
1339 modprobe_r("nf_conntrack_ipv6");
1340 modprobe_r("ip6t_LOG");
1341 modprobe_r("ip6t_REJECT");
1342 #endif
1343 #ifdef LINUX26
1344 modprobe_r("xt_layer7");
1345 modprobe_r("xt_recent");
1346 modprobe_r("xt_HL");
1347 modprobe_r("xt_length");
1348 modprobe_r("xt_web");
1349 modprobe_r("xt_webmon");
1350 modprobe_r("xt_dscp");
1351 #else
1352 modprobe_r("ipt_layer7");
1353 modprobe_r("ipt_recent");
1354 modprobe_r("ipt_TTL");
1355 modprobe_r("ipt_web");
1356 modprobe_r("ipt_webmon");
1357 modprobe_r("ipt_dscp");
1358 #endif
1359 modprobe_r("ipt_ipp2p");
1361 unlink("/var/webmon/domain");
1362 unlink("/var/webmon/search");
1364 #ifdef TCONFIG_OPENVPN
1365 run_vpn_firewall_scripts();
1366 #endif
1367 run_nvscript("script_fire", NULL, 1);
1369 simple_unlock("firewall");
1370 return 0;
1373 int stop_firewall(void)
1375 led(LED_DMZ, 0);
1376 return 0;
1379 #ifdef DEBUG_IPTFILE
1380 void create_test_iptfile(void)
1382 debug_only = 1;
1383 start_firewall();
1384 debug_only = 0;
1386 #endif