rc: reset iface IP address on wan [re]connect
[tomato.git] / release / src / router / rc / firewall.c
blob544a6be24488ee5ce2913d7cf5f66e472f59e589
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 system("cp /proc/webmon_recent_domains /var/webmon/domain");
368 system("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();
458 p = nvram_safe_get("nf_ttl");
459 if (strncmp(p, "c:", 2) == 0) {
460 p += 2;
461 ttl = atoi(p);
462 p = (ttl >= 0 && ttl <= 255) ? "set" : NULL;
464 else if ((ttl = atoi(p)) != 0) {
465 if (ttl > 0) {
466 p = "inc";
468 else {
469 ttl = -ttl;
470 p = "dec";
472 if (ttl > 255) p = NULL;
474 else p = NULL;
476 if (p) {
477 #ifdef LINUX26
478 modprobe("xt_HL");
479 #else
480 modprobe("ipt_TTL");
481 #endif
482 // set TTL on primary WAN iface only
483 wanface = wanfaces.iface[0].name;
484 ip46t_write(
485 "-I PREROUTING -i %s -j TTL --ttl-%s %d\n"
486 "-I POSTROUTING -o %s -j TTL --ttl-%s %d\n",
487 wanface, p, ttl,
488 wanface, p, ttl);
492 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 if (gateway_mode) {
519 strlcpy(lanaddr, nvram_safe_get("lan_ipaddr"), sizeof(lanaddr));
520 strlcpy(lanmask, nvram_safe_get("lan_netmask"), sizeof(lanmask));
522 for (i = 0; i < wanfaces.count; ++i) {
523 if (*(wanfaces.iface[i].name)) {
524 // chain_wan_prerouting
525 if (wanup)
526 ipt_write("-A PREROUTING -d %s -j %s\n",
527 wanfaces.iface[i].ip, chain_wan_prerouting);
529 // Drop incoming packets which destination IP address is to our LAN side directly
530 ipt_write("-A PREROUTING -i %s -d %s/%s -j DROP\n",
531 wanfaces.iface[i].name,
532 lanaddr, lanmask); // note: ipt will correct lanaddr
536 if (wanup) {
537 if (nvram_match("dns_intcpt", "1")) {
538 ipt_write("-A PREROUTING -p udp -s %s/%s ! -d %s/%s --dport 53 -j DNAT --to-destination %s\n",
539 lanaddr, lanmask,
540 lanaddr, lanmask,
541 lanaddr);
544 // ICMP packets are always redirected to INPUT chains
545 ipt_write("-A %s -p icmp -j DNAT --to-destination %s\n", chain_wan_prerouting, lanaddr);
547 ipt_forward(IPT_TABLE_NAT);
548 ipt_triggered(IPT_TABLE_NAT);
551 if (nvram_get_int("upnp_enable") & 3) {
552 ipt_write(":upnp - [0:0]\n");
553 if (wanup) {
554 // ! for loopback (all) to work
555 ipt_write("-A %s -j upnp\n", chain_wan_prerouting);
557 else {
558 for (i = 0; i < wanfaces.count; ++i) {
559 if (*(wanfaces.iface[i].name)) {
560 ipt_write("-A PREROUTING -i %s -j upnp\n", wanfaces.iface[i].name);
566 if (wanup) {
567 if (dmz_dst(dst)) {
568 strlcpy(t, nvram_safe_get("dmz_sip"), sizeof(t));
569 p = t;
570 do {
571 if ((c = strchr(p, ',')) != NULL) *c = 0;
572 if (ipt_source_strict(p, src, "dmz", NULL))
573 ipt_write("-A %s %s -j DNAT --to-destination %s\n", chain_wan_prerouting, src, dst);
574 if (!c) break;
575 p = c + 1;
576 } while (*p);
580 p = "";
581 #ifdef TCONFIG_IPV6
582 switch (get_ipv6_service()) {
583 case IPV6_6IN4:
584 // avoid NATing proto-41 packets when using 6in4 tunnel
585 p = "-p ! 41";
586 break;
588 #endif
590 for (i = 0; i < wanfaces.count; ++i) {
591 if (*(wanfaces.iface[i].name)) {
592 if ((!wanup) || (nvram_get_int("net_snat") != 1))
593 ipt_write("-A POSTROUTING %s -o %s -j MASQUERADE\n", p, wanfaces.iface[i].name);
594 else
595 ipt_write("-A POSTROUTING %s -o %s -j SNAT --to-source %s\n", p, wanfaces.iface[i].name, wanfaces.iface[i].ip);
599 switch (nvram_get_int("nf_loopback")) {
600 case 1: // 1 = forwarded-only
601 case 2: // 2 = disable
602 break;
603 default: // 0 = all (same as block_loopback=0)
604 ipt_write("-A POSTROUTING -o %s -s %s/%s -d %s/%s -j SNAT --to-source %s\n",
605 lanface,
606 lanaddr, lanmask,
607 lanaddr, lanmask,
608 lanaddr);
609 break;
612 ipt_write("COMMIT\n");
615 // -----------------------------------------------------------------------------
616 // FILTER
617 // -----------------------------------------------------------------------------
619 static void filter_input(void)
621 char s[64];
622 char t[512];
623 char *en;
624 char *sec;
625 char *hit;
626 int n;
627 char *p, *c;
629 if ((nvram_get_int("nf_loopback") != 0) && (wanup)) { // 0 = all
630 for (n = 0; n < wanfaces.count; ++n) {
631 if (*(wanfaces.iface[n].name)) {
632 ipt_write("-A INPUT -i %s -d %s -j DROP\n", lanface, wanfaces.iface[n].ip);
637 ipt_write(
638 "-A INPUT -m state --state INVALID -j DROP\n"
639 "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n");
641 strlcpy(s, nvram_safe_get("ne_shlimit"), sizeof(s));
642 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && ((n = atoi(en) & 3) != 0)) {
644 ? what if the user uses the start button in GUI ?
645 if (nvram_get_int("telnetd_eas"))
646 if (nvram_get_int("sshd_eas"))
648 #ifdef LINUX26
649 modprobe("xt_recent");
650 #else
651 modprobe("ipt_recent");
652 #endif
654 ipt_write(
655 "-N shlimit\n"
656 "-A shlimit -m recent --set --name shlimit\n"
657 "-A shlimit -m recent --update --hitcount %d --seconds %s --name shlimit -j %s\n",
658 atoi(hit) + 1, sec, chain_in_drop);
660 if (n & 1) {
661 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_port"));
662 if (nvram_get_int("sshd_remote") && nvram_invmatch("sshd_rport", nvram_safe_get("sshd_port"))) {
663 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_rport"));
666 if (n & 2) ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("telnetd_port"));
669 #ifdef TCONFIG_FTP
670 strlcpy(s, nvram_safe_get("ftp_limit"), sizeof(s));
671 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && (atoi(en)) && (nvram_get_int("ftp_enable") == 1)) {
672 #ifdef LINUX26
673 modprobe("xt_recent");
674 #else
675 modprobe("ipt_recent");
676 #endif
678 ipt_write(
679 "-N ftplimit\n"
680 "-A ftplimit -m recent --set --name ftp\n"
681 "-A ftplimit -m recent --update --hitcount %d --seconds %s --name ftp -j %s\n",
682 atoi(hit) + 1, sec, chain_in_drop);
683 ipt_write("-A INPUT -p tcp --dport %s -m state --state NEW -j ftplimit\n", nvram_safe_get("ftp_port"));
685 #endif
687 ipt_write(
688 "-A INPUT -i %s -j ACCEPT\n"
689 "-A INPUT -i lo -j ACCEPT\n",
690 lanface);
692 #ifdef TCONFIG_IPV6
693 switch (get_ipv6_service()) {
694 case IPV6_6IN4:
695 // Accept ICMP requests from the remote tunnel endpoint
696 if ((p = nvram_get("ipv6_tun_v4end")) && *p && strcmp(p, "0.0.0.0") != 0)
697 ipt_write("-A INPUT -p icmp -s %s -j %s\n", p, chain_in_accept);
698 ipt_write("-A INPUT -p 41 -j %s\n", chain_in_accept);
699 break;
701 #endif
703 // ICMP request from WAN interface
704 if (nvram_match("block_wan", "0")) {
705 // allow ICMP packets to be received, but restrict the flow to avoid ping flood attacks
706 ipt_write("-A INPUT -p icmp -m limit --limit 1/second -j %s\n", chain_in_accept);
707 // allow udp traceroute packets
708 ipt_write("-A INPUT -p udp -m udp --dport 33434:33534 -m limit --limit 5/second -j %s\n", chain_in_accept);
711 /* Accept incoming packets from broken dhcp servers, which are sending replies
712 * from addresses other than used for query. This could lead to a lower level
713 * of security, so allow to disable it via nvram variable.
715 if (nvram_invmatch("dhcp_pass", "0") && using_dhcpc()) {
716 ipt_write("-A INPUT -p udp --sport 67 --dport 68 -j %s\n", chain_in_accept);
719 strlcpy(t, nvram_safe_get("rmgt_sip"), sizeof(t));
720 p = t;
721 do {
722 if ((c = strchr(p, ',')) != NULL) *c = 0;
724 if (ipt_source(p, s, "remote management", NULL)) {
726 if (remotemanage) {
727 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
728 s, nvram_safe_get("http_wanport"), chain_in_accept);
731 if (nvram_get_int("sshd_remote")) {
732 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
733 s, nvram_safe_get("sshd_rport"), chain_in_accept);
737 if (!c) break;
738 p = c + 1;
739 } while (*p);
741 #ifdef TCONFIG_FTP // !!TB - FTP Server
742 if (nvram_match("ftp_enable", "1")) { // FTP WAN access enabled
743 strlcpy(t, nvram_safe_get("ftp_sip"), sizeof(t));
744 p = t;
745 do {
746 if ((c = strchr(p, ',')) != NULL) *c = 0;
747 if (ipt_source(p, s, "ftp", "remote access")) {
748 ipt_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
749 s, nvram_safe_get("ftp_port"), chain_in_accept);
751 if (!c) break;
752 p = c + 1;
753 } while (*p);
755 #endif
757 // IGMP query from WAN interface
758 if (nvram_match("multicast_pass", "1")) {
759 ipt_write("-A INPUT -p igmp -d 224.0.0.0/4 -j ACCEPT\n");
760 ipt_write("-A INPUT -p udp -d 224.0.0.0/4 ! --dport 1900 -j ACCEPT\n");
763 // Routing protocol, RIP, accept
764 if (nvram_invmatch("dr_wan_rx", "0")) {
765 ipt_write("-A INPUT -p udp -m udp --dport 520 -j ACCEPT\n");
768 // if logging
769 if (*chain_in_drop == 'l') {
770 ipt_write( "-A INPUT -j %s\n", chain_in_drop);
773 // default policy: DROP
776 // clamp TCP MSS to PMTU of WAN interface (IPv4 only?)
777 static void clampmss(void)
779 #if 1
780 ipt_write("-A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu\n");
781 #else
782 int rmtu = nvram_get_int("wan_run_mtu");
783 ipt_write("-A FORWARD -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss %d: -j TCPMSS ", rmtu - 39);
784 if (rmtu < 576) {
785 ipt_write("--clamp-mss-to-pmtu\n");
787 else {
788 ipt_write("--set-mss %d\n", rmtu - 40);
790 #endif
793 static void filter_forward(void)
795 char dst[64];
796 char src[64];
797 char t[512];
798 char *p, *c;
799 int i;
801 #ifdef TCONFIG_IPV6
802 ip6t_write(
803 "-A FORWARD -m rt --rt-type 0 -j DROP\n");
804 #endif
806 ip46t_write(
807 "-A FORWARD -i %s -o %s -j ACCEPT\n", // accept all lan to lan
808 lanface, lanface);
810 // IPv4 only ?
811 ipt_write(
812 "-A FORWARD -m state --state INVALID -j DROP\n"); // drop if INVALID state
814 // clamp tcp mss to pmtu
815 clampmss();
817 if (wanup) {
818 ipt_restrictions();
820 ipt_layer7_inbound();
823 ipt_webmon();
825 ip46t_write(
826 ":wanin - [0:0]\n"
827 ":wanout - [0:0]\n"
828 "-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT\n"); // already established or related (via helper)
830 #ifdef TCONFIG_IPV6
831 // Filter out invalid WAN->WAN connections
832 if (*wan6face)
833 ip6t_write("-A FORWARD -o %s ! -i %s -j %s\n", wan6face, lanface, chain_in_drop);
835 #ifdef LINUX26
836 modprobe("xt_length");
837 ip6t_write("-A FORWARD -p ipv6-nonxt -m length --length 40 -j ACCEPT\n");
838 #endif
840 // ICMPv6 rules
841 for (i = 0; i < sizeof(allowed_icmpv6)/sizeof(int); ++i) {
842 ip6t_write("-A FORWARD -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_icmpv6[i], chain_in_accept);
845 if (*wan6face) {
846 ip6t_write(
847 "-A FORWARD -i %s -j wanin\n" // generic from wan
848 "-A FORWARD -o %s -j wanout\n", // generic to wan
849 wan6face, wan6face);
851 #endif
853 for (i = 0; i < wanfaces.count; ++i) {
854 if (*(wanfaces.iface[i].name)) {
855 ipt_write(
856 "-A FORWARD -i %s -j wanin\n" // generic from wan
857 "-A FORWARD -o %s -j wanout\n", // generic to wan
858 wanfaces.iface[i].name, wanfaces.iface[i].name);
862 ip46t_write("-A FORWARD -i %s -j %s\n", // from lan
863 lanface, chain_out_accept);
865 // IPv4 only
866 if (nvram_get_int("upnp_enable") & 3) {
867 ipt_write(":upnp - [0:0]\n");
868 for (i = 0; i < wanfaces.count; ++i) {
869 if (*(wanfaces.iface[i].name)) {
870 ipt_write("-A FORWARD -i %s -j upnp\n",
871 wanfaces.iface[i].name);
876 if (wanup) {
877 if (nvram_match("multicast_pass", "1")) {
878 ipt_write("-A wanin -p udp -d 224.0.0.0/4 -j %s\n", chain_in_accept);
880 ipt_triggered(IPT_TABLE_FILTER);
881 ipt_forward(IPT_TABLE_FILTER);
882 #ifdef TCONFIG_IPV6
883 ip6t_forward();
884 #endif
886 if (dmz_dst(dst)) {
887 strlcpy(t, nvram_safe_get("dmz_sip"), sizeof(t));
888 p = t;
889 do {
890 if ((c = strchr(p, ',')) != NULL) *c = 0;
891 if (ipt_source_strict(p, src, "dmz", NULL))
892 ipt_write("-A FORWARD -o %s %s -d %s -j %s\n", lanface, src, dst, chain_in_accept);
893 if (!c) break;
894 p = c + 1;
895 } while (*p);
899 // default policy: DROP
902 static void filter_log(void)
904 int n;
905 char limit[128];
907 n = nvram_get_int("log_limit");
908 if ((n >= 1) && (n <= 9999)) {
909 sprintf(limit, "-m limit --limit %d/m", n);
911 else {
912 limit[0] = 0;
915 #ifdef TCONFIG_IPV6
916 modprobe("ip6t_LOG");
917 #endif
918 if ((*chain_in_drop == 'l') || (*chain_out_drop == 'l')) {
919 ip46t_write(
920 ":logdrop - [0:0]\n"
921 "-A logdrop -m state --state NEW %s -j LOG --log-prefix \"DROP \""
922 #ifdef LINUX26
923 " --log-macdecode"
924 #endif
925 " --log-tcp-sequence --log-tcp-options --log-ip-options\n"
926 "-A logdrop -j DROP\n"
927 ":logreject - [0:0]\n"
928 "-A logreject %s -j LOG --log-prefix \"REJECT \""
929 #ifdef LINUX26
930 " --log-macdecode"
931 #endif
932 " --log-tcp-sequence --log-tcp-options --log-ip-options\n"
933 "-A logreject -p tcp -j REJECT --reject-with tcp-reset\n",
934 limit, limit);
936 if ((*chain_in_accept == 'l') || (*chain_out_accept == 'l')) {
937 ip46t_write(
938 ":logaccept - [0:0]\n"
939 "-A logaccept -m state --state NEW %s -j LOG --log-prefix \"ACCEPT \""
940 #ifdef LINUX26
941 " --log-macdecode"
942 #endif
943 " --log-tcp-sequence --log-tcp-options --log-ip-options\n"
944 "-A logaccept -j ACCEPT\n",
945 limit);
949 #ifdef TCONFIG_IPV6
950 static void filter6_input(void)
952 char s[128];
953 char t[512];
954 char *en;
955 char *sec;
956 char *hit;
957 int n;
958 char *p, *c;
960 // RFC-4890, sec. 4.4.1
961 const int allowed_local_icmpv6[] =
962 { 130, 131, 132, 133, 134, 135, 136,
963 141, 142, 143,
964 148, 149, 151, 152, 153 };
966 ip6t_write(
967 "-A INPUT -m rt --rt-type 0 -j %s\n"
968 /* "-A INPUT -m state --state INVALID -j DROP\n" */
969 "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n",
970 chain_in_drop);
972 #ifdef LINUX26
973 modprobe("xt_length");
974 ip6t_write("-A INPUT -p ipv6-nonxt -m length --length 40 -j ACCEPT\n");
975 #endif
977 strlcpy(s, nvram_safe_get("ne_shlimit"), sizeof(s));
978 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && ((n = atoi(en) & 3) != 0)) {
979 #ifdef LINUX26
980 modprobe("xt_recent");
981 #else
982 modprobe("ipt_recent");
983 #endif
985 ip6t_write(
986 "-N shlimit\n"
987 "-A shlimit -m recent --set --name shlimit\n"
988 "-A shlimit -m recent --update --hitcount %d --seconds %s --name shlimit -j %s\n",
989 atoi(hit) + 1, sec, chain_in_drop);
991 if (n & 1) {
992 ip6t_write("-A INPUT -i %s -p tcp --dport %s -m state --state NEW -j shlimit\n", lanface, nvram_safe_get("sshd_port"));
993 if (nvram_get_int("sshd_remote") && nvram_invmatch("sshd_rport", nvram_safe_get("sshd_port"))) {
994 ip6t_write("-A INPUT -p tcp --dport %s -m state --state NEW -j shlimit\n", nvram_safe_get("sshd_rport"));
997 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"));
1000 #ifdef TCONFIG_FTP
1001 strlcpy(s, nvram_safe_get("ftp_limit"), sizeof(s));
1002 if ((vstrsep(s, ",", &en, &hit, &sec) == 3) && (atoi(en)) && (nvram_get_int("ftp_enable") == 1)) {
1003 #ifdef LINUX26
1004 modprobe("xt_recent");
1005 #else
1006 modprobe("ipt_recent");
1007 #endif
1009 ip6t_write(
1010 "-N ftplimit\n"
1011 "-A ftplimit -m recent --set --name ftp\n"
1012 "-A ftplimit -m recent --update --hitcount %d --seconds %s --name ftp -j %s\n",
1013 atoi(hit) + 1, sec, chain_in_drop);
1014 ip6t_write("-A INPUT -p tcp --dport %s -m state --state NEW -j ftplimit\n", nvram_safe_get("ftp_port"));
1016 #endif // TCONFIG_FTP
1018 ip6t_write(
1019 "-A INPUT -i %s -j ACCEPT\n" // anything coming from LAN
1020 "-A INPUT -i lo -j ACCEPT\n",
1021 lanface );
1023 switch (get_ipv6_service()) {
1024 case IPV6_NATIVE_DHCP:
1025 // allow responses from the dhcpv6 server
1026 ip6t_write("-A INPUT -p udp --dport 546 -j %s\n", chain_in_accept);
1027 break;
1030 // ICMPv6 rules
1031 for (n = 0; n < sizeof(allowed_icmpv6)/sizeof(int); n++) {
1032 ip6t_write("-A INPUT -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_icmpv6[n], chain_in_accept);
1034 for (n = 0; n < sizeof(allowed_local_icmpv6)/sizeof(int); n++) {
1035 ip6t_write("-A INPUT -p ipv6-icmp --icmpv6-type %i -j %s\n", allowed_local_icmpv6[n], chain_in_accept);
1038 // Remote Managment
1039 strlcpy(t, nvram_safe_get("rmgt_sip"), sizeof(t));
1040 p = t;
1041 do {
1042 if ((c = strchr(p, ',')) != NULL) *c = 0;
1044 if (ip6t_source(p, s, "remote management", NULL)) {
1046 if (remotemanage) {
1047 ip6t_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
1048 s, nvram_safe_get("http_wanport"), chain_in_accept);
1051 if (nvram_get_int("sshd_remote")) {
1052 ip6t_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
1053 s, nvram_safe_get("sshd_rport"), chain_in_accept);
1057 if (!c) break;
1058 p = c + 1;
1059 } while (*p);
1061 #ifdef TCONFIG_FTP
1062 // FTP server
1063 if (nvram_match("ftp_enable", "1")) { // FTP WAN access enabled
1064 strlcpy(t, nvram_safe_get("ftp_sip"), sizeof(t));
1065 p = t;
1066 do {
1067 if ((c = strchr(p, ',')) != NULL) *c = 0;
1068 if (ip6t_source(p, s, "ftp", "remote access")) {
1069 ip6t_write("-A INPUT -p tcp %s -m tcp --dport %s -j %s\n",
1070 s, nvram_safe_get("ftp_port"), chain_in_accept);
1072 if (!c) break;
1073 p = c + 1;
1074 } while (*p);
1076 #endif
1078 // if logging
1079 if (*chain_in_drop == 'l') {
1080 ip6t_write( "-A INPUT -j %s\n", chain_in_drop);
1083 // default policy: DROP
1086 #endif
1088 static void filter_table(void)
1090 ip46t_write(
1091 "*filter\n"
1092 ":INPUT DROP [0:0]\n"
1093 ":OUTPUT ACCEPT [0:0]\n"
1096 filter_log();
1098 filter_input();
1099 #ifdef TCONFIG_IPV6
1100 filter6_input();
1101 ip6t_write("-A OUTPUT -m rt --rt-type 0 -j %s\n", chain_in_drop);
1102 #endif
1104 if ((gateway_mode) || (nvram_match("wk_mode_x", "1"))) {
1105 ip46t_write(":FORWARD DROP [0:0]\n");
1106 filter_forward();
1108 else {
1109 ip46t_write(":FORWARD ACCEPT [0:0]\n");
1110 clampmss();
1112 ip46t_write("COMMIT\n");
1116 // -----------------------------------------------------------------------------
1118 int start_firewall(void)
1120 DIR *dir;
1121 struct dirent *dirent;
1122 char s[256];
1123 char *c, *wanface;
1124 int n;
1125 int wanproto;
1126 char *iptrestore_argv[] = { "iptables-restore", (char *)ipt_fname, NULL };
1127 #ifdef TCONFIG_IPV6
1128 char *ip6trestore_argv[] = { "ip6tables-restore", (char *)ip6t_fname, NULL };
1129 #endif
1131 simple_lock("firewall");
1132 simple_lock("restrictions");
1134 wanup = check_wanup();
1136 f_write_string("/proc/sys/net/ipv4/tcp_syncookies", nvram_get_int("ne_syncookies") ? "1" : "0", 0, 0);
1138 /* NAT performance tweaks
1139 * These values can be overriden later if needed via firewall script
1141 f_write_string("/proc/sys/net/core/netdev_max_backlog", "3072", 0, 0);
1142 f_write_string("/proc/sys/net/core/somaxconn", "3072", 0, 0);
1143 f_write_string("/proc/sys/net/ipv4/tcp_max_syn_backlog", "8192", 0, 0);
1144 f_write_string("/proc/sys/net/ipv4/tcp_fin_timeout", "30", 0, 0);
1145 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_intvl", "24", 0, 0);
1146 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_probes", "3", 0, 0);
1147 f_write_string("/proc/sys/net/ipv4/tcp_keepalive_time", "1800", 0, 0);
1148 f_write_string("/proc/sys/net/ipv4/tcp_retries2", "5", 0, 0);
1149 f_write_string("/proc/sys/net/ipv4/tcp_syn_retries", "3", 0, 0);
1150 f_write_string("/proc/sys/net/ipv4/tcp_synack_retries", "3", 0, 0);
1151 f_write_string("/proc/sys/net/ipv4/tcp_tw_recycle", "1", 0, 0);
1152 f_write_string("/proc/sys/net/ipv4/tcp_tw_reuse", "1", 0, 0);
1154 /* DoS-related tweaks */
1155 f_write_string("/proc/sys/net/ipv4/icmp_ignore_bogus_error_responses", "1", 0, 0);
1156 f_write_string("/proc/sys/net/ipv4/tcp_rfc1337", "1", 0, 0);
1157 f_write_string("/proc/sys/net/ipv4/ip_local_port_range", "1024 65535", 0, 0);
1159 wanproto = get_wan_proto();
1160 f_write_string("/proc/sys/net/ipv4/ip_dynaddr", (wanproto == WP_DISABLED || wanproto == WP_STATIC) ? "0" : "1", 0, 0);
1162 #ifdef TCONFIG_EMF
1163 /* Force IGMPv2 due EMF limitations */
1164 if (nvram_get_int("emf_enable")) {
1165 f_write_string("/proc/sys/net/ipv4/conf/default/force_igmp_version", "2", 0, 0);
1166 f_write_string("/proc/sys/net/ipv4/conf/all/force_igmp_version", "2", 0, 0);
1168 #endif
1170 n = nvram_get_int("log_in");
1171 chain_in_drop = (n & 1) ? "logdrop" : "DROP";
1172 chain_in_accept = (n & 2) ? "logaccept" : "ACCEPT";
1174 n = nvram_get_int("log_out");
1175 chain_out_drop = (n & 1) ? "logdrop" : "DROP";
1176 chain_out_reject = (n & 1) ? "logreject" : "REJECT --reject-with tcp-reset";
1177 chain_out_accept = (n & 2) ? "logaccept" : "ACCEPT";
1179 // if (nvram_match("nf_drop_reset", "1")) chain_out_drop = chain_out_reject;
1181 strlcpy(lanface, nvram_safe_get("lan_ifname"), IFNAMSIZ);
1183 memcpy(&wanfaces, get_wanfaces(), sizeof(wanfaces));
1184 wanface = wanfaces.iface[0].name;
1185 #ifdef TCONFIG_IPV6
1186 strlcpy(wan6face, get_wan6face(), sizeof(wan6face));
1187 #endif
1189 strlcpy(s, nvram_safe_get("lan_ipaddr"), sizeof(s));
1190 if ((c = strrchr(s, '.')) != NULL) *(c + 1) = 0;
1191 strlcpy(lan_cclass, s, sizeof(lan_cclass));
1194 block obviously spoofed IP addresses
1196 rp_filter - BOOLEAN
1197 1 - do source validation by reversed path, as specified in RFC1812
1198 Recommended option for single homed hosts and stub network
1199 routers. Could cause troubles for complicated (not loop free)
1200 networks running a slow unreliable protocol (sort of RIP),
1201 or using static routes.
1202 0 - No source validation.
1204 c = nvram_get("wan_ifname");
1205 /* mcast needs rp filter to be turned off only for non default iface */
1206 if (!(nvram_match("multicast_pass", "1")) || strcmp(wanface, c) == 0) c = NULL;
1208 if ((dir = opendir("/proc/sys/net/ipv4/conf")) != NULL) {
1209 while ((dirent = readdir(dir)) != NULL) {
1210 sprintf(s, "/proc/sys/net/ipv4/conf/%s/rp_filter", dirent->d_name);
1211 f_write_string(s, (c && strcmp(dirent->d_name, c) == 0) ? "0" : "1", 0, 0);
1213 closedir(dir);
1216 remotemanage = 0;
1217 gateway_mode = !nvram_match("wk_mode", "router");
1218 if (gateway_mode) {
1219 /* Remote management */
1220 if (nvram_match("remote_management", "1") && nvram_invmatch("http_wanport", "") &&
1221 nvram_invmatch("http_wanport", "0")) remotemanage = 1;
1224 if ((ipt_file = fopen(ipt_fname, "w")) == NULL) {
1225 notice_set("iptables", "Unable to create iptables restore file");
1226 simple_unlock("firewall");
1227 return 0;
1230 #ifdef TCONFIG_IPV6
1231 if ((ip6t_file = fopen(ip6t_fname, "w")) == NULL) {
1232 notice_set("ip6tables", "Unable to create ip6tables restore file");
1233 simple_unlock("firewall");
1234 return 0;
1236 modprobe("nf_conntrack_ipv6");
1237 modprobe("ip6t_REJECT");
1238 #endif
1240 mangle_table();
1241 nat_table();
1242 filter_table();
1244 fclose(ipt_file);
1245 ipt_file = NULL;
1247 #ifdef TCONFIG_IPV6
1248 fclose(ip6t_file);
1249 ip6t_file = NULL;
1250 #endif
1252 #ifdef DEBUG_IPTFILE
1253 if (debug_only) {
1254 simple_unlock("firewall");
1255 simple_unlock("restrictions");
1256 return 0;
1258 #endif
1260 save_webmon();
1262 if (nvram_get_int("upnp_enable") & 3) {
1263 f_write("/etc/upnp/save", NULL, 0, 0, 0);
1264 if (killall("miniupnpd", SIGUSR2) == 0) {
1265 f_wait_notexists("/etc/upnp/save", 5);
1269 notice_set("iptables", "");
1270 if (_eval(iptrestore_argv, ">/var/notice/iptables", 0, NULL) == 0) {
1271 led(LED_DIAG, 0);
1272 notice_set("iptables", "");
1274 else {
1275 sprintf(s, "%s.error", ipt_fname);
1276 rename(ipt_fname, s);
1277 syslog(LOG_CRIT, "Error while loading rules. See %s file.", s);
1278 led(LED_DIAG, 1);
1282 -P INPUT DROP
1283 -F INPUT
1284 -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
1285 -A INPUT -i br0 -j ACCEPT
1287 -P FORWARD DROP
1288 -F FORWARD
1289 -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
1290 -A FORWARD -i br0 -j ACCEPT
1295 #ifdef TCONFIG_IPV6
1296 if (ipv6_enabled()) {
1297 notice_set("ip6tables", "");
1298 if (_eval(ip6trestore_argv, ">/var/notice/ip6tables", 0, NULL) == 0) {
1299 notice_set("ip6tables", "");
1301 else {
1302 sprintf(s, "%s.error", ip6t_fname);
1303 rename(ip6t_fname, s);
1304 syslog(LOG_CRIT, "Error while loading rules. See %s file.", s);
1305 led(LED_DIAG, 1);
1308 else {
1309 eval("ip6tables", "-F");
1310 eval("ip6tables", "-t", "mangle", "-F");
1312 #endif
1314 if (nvram_get_int("upnp_enable") & 3) {
1315 f_write("/etc/upnp/load", NULL, 0, 0, 0);
1316 killall("miniupnpd", SIGUSR2);
1319 simple_unlock("restrictions");
1320 sched_restrictions();
1321 enable_ip_forward();
1323 led(LED_DMZ, dmz_dst(NULL));
1325 #ifdef TCONFIG_IPV6
1326 modprobe_r("nf_conntrack_ipv6");
1327 modprobe_r("ip6t_LOG");
1328 modprobe_r("ip6t_REJECT");
1329 #endif
1330 #ifdef LINUX26
1331 modprobe_r("xt_layer7");
1332 modprobe_r("xt_recent");
1333 modprobe_r("xt_HL");
1334 modprobe_r("xt_length");
1335 modprobe_r("xt_web");
1336 modprobe_r("xt_webmon");
1337 modprobe_r("xt_dscp");
1338 #else
1339 modprobe_r("ipt_layer7");
1340 modprobe_r("ipt_recent");
1341 modprobe_r("ipt_TTL");
1342 modprobe_r("ipt_web");
1343 modprobe_r("ipt_webmon");
1344 modprobe_r("ipt_dscp");
1345 #endif
1346 modprobe_r("ipt_ipp2p");
1348 unlink("/var/webmon/domain");
1349 unlink("/var/webmon/search");
1351 #ifdef TCONFIG_OPENVPN
1352 run_vpn_firewall_scripts();
1353 #endif
1354 run_nvscript("script_fire", NULL, 1);
1356 simple_unlock("firewall");
1357 return 0;
1360 int stop_firewall(void)
1362 led(LED_DMZ, 0);
1363 return 0;
1366 #ifdef DEBUG_IPTFILE
1367 void create_test_iptfile(void)
1369 debug_only = 1;
1370 start_firewall();
1371 debug_only = 0;
1373 #endif