Merge branch 'Toastman-RT' into Toastman-RT-N
[tomato.git] / release / src / router / rc / restrict.c
blob99a9c56fe725e0b8e2fae4b17699f1c37f8be219
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "rc.h"
9 #include <time.h>
12 #define MAX_NRULES 50
14 static inline void unsched_restrictions(void)
16 system("cru d rcheck");
19 void sched_restrictions(void)
21 system("rcheck");
24 static int in_sched(int now_mins, int now_dow, int sched_begin, int sched_end, int sched_dow)
26 // all day
27 if ((sched_begin < 0) || (sched_end < 0)) {
28 return (sched_dow & now_dow) != 0;
31 // simple min to max
32 if (sched_begin < sched_end) {
33 return (((sched_dow & now_dow) != 0) && (now_mins >= sched_begin) && (now_mins < sched_end));
36 // 15:00 - 01:00 = 15:00 Sun to 01:00 Mon
37 // 12:00 - 12:00 = 12:00 Sun to 12:00 Mon
39 if ((now_dow & sched_dow) != 0) {
40 if (now_mins >= sched_begin) return 1;
43 // ror now_dow, 1
44 if (now_dow == 1) now_dow = (1 << 6);
45 else now_dow >>= 1;
47 if ((now_dow & sched_dow) != 0) {
48 if (now_mins < sched_end) return 1;
51 // printf("now_mins=%d sched_end=%d now_dow=%d sched_dow=%d\n", now_mins, sched_end, now_dow, sched_dow);
52 return 0;
55 static int radio_on(int idx, int unit, int subunit, void *param)
57 return nvram_match(wl_nvname("radio", unit, 0), "1");
60 int rcheck_main(int argc, char *argv[])
62 char buf[256];
63 char *p;
64 int sched_begin;
65 int sched_end;
66 int sched_dow;
67 time_t now;
68 struct tm *tms;
69 int now_dow;
70 int now_mins;
71 int n;
72 int nrule;
73 char comp;
74 int insch;
75 unsigned long long activated;
76 int count;
77 int radio;
78 int r;
79 #ifdef TCONFIG_IPV6
80 int r6;
81 #endif
82 #ifdef LINUX26
83 int ipt_active;
84 #endif
86 if (!nvram_contains_word("log_events", "acre")) {
87 setlogmask(LOG_MASK(LOG_EMERG)); // can't set to 0
90 simple_lock("restrictions");
92 now = time(0);
93 if (now < Y2K) {
94 if (!nvram_match("rrules_timewarn", "1")) {
95 nvram_set("rrules_timewarn", "1");
96 syslog(LOG_INFO, "Time not yet set. Only \"all day, everyday\" restrictions will be activated.");
98 now_mins = now_dow = 0;
100 else {
101 tms = localtime(&now);
102 now_dow = 1 << tms->tm_wday;
103 now_mins = (tms->tm_hour * 60) + tms->tm_min;
106 #ifdef LINUX26
107 ipt_active = 0;
108 #endif
110 activated = strtoull(nvram_safe_get("rrules_activated"), NULL, 16);
111 count = 0;
112 radio = foreach_wif(0, NULL, radio_on) ? -1 : -2;
113 for (nrule = 0; nrule < MAX_NRULES; ++nrule) {
114 sprintf(buf, "rrule%d", nrule);
115 if ((p = nvram_get(buf)) == NULL) continue;
116 if (sscanf(p, "%d|%d|%d|%d|%c", &n, &sched_begin, &sched_end, &sched_dow, &comp) != 5) continue;
117 if (n == 0) continue;
119 ++count;
121 if (now < Y2K) {
122 if ((sched_begin >= 0) || (sched_end >= 0) || (sched_dow != 0x7F)) continue;
123 insch = 1;
125 else {
126 insch = in_sched(now_mins, now_dow, sched_begin, sched_end, sched_dow);
129 #ifdef LINUX26
130 if ((insch) && (comp != '~'))
131 ++ipt_active;
132 #endif
134 n = 1 << nrule;
135 if ((insch) == ((activated & n) != 0)) {
136 continue;
139 syslog(LOG_INFO, "%sctivating rule %d", insch ? "A" : "Dea", nrule);
141 if (comp == '~') {
142 if ((radio != 0) && (radio != -2)) radio = !insch;
144 else {
145 sprintf(buf, "r%s%02d", (comp != '|') ? "dev" : "res", nrule);
147 r = eval("iptables", "-D", "restrict", "-j", buf);
148 if (insch) {
149 // ignore error above (if any)
151 r = eval("iptables", "-A", "restrict", "-j", buf);
154 #ifdef TCONFIG_IPV6
155 r6 = eval("ip6tables", "-D", "restrict", "-j", buf);
156 if (ipv6_enabled()) {
157 if (insch) {
158 // ignore error above (if any)
160 r6 = eval("ip6tables", "-A", "restrict", "-j", buf);
162 r |= r6;
164 #endif
166 if (r != 0) {
167 syslog(LOG_ERR, "Iptables: %sactivating chain \"%s\" failed. Retrying in 15 minutes.",
168 insch ? "" : "de", buf);
169 continue;
173 if (insch) activated |= n;
174 else activated &= ~n;
177 sprintf(buf, "%llx", activated);
178 nvram_set("rrules_activated", buf);
180 if (count > 0) {
181 if ((argc != 2) || (strcmp(argv[1], "--cron") != 0)) {
182 system("cru a rcheck '*/15 * * * * rcheck --cron'");
185 else {
186 unsched_restrictions();
189 if (radio >= 0) {
190 nvram_set("rrules_radio", radio ? "0" : "1");
191 #if 1
192 // changed for dual radio support
193 _dprintf("%s: radio = %d\n", __FUNCTION__, radio);
194 eval("radio", radio ? "on" : "off");
195 #else
196 if (get_radio() != radio) {
197 _dprintf("%s: radio = %d\n", __FUNCTION__, radio);
198 eval("radio", radio ? "on" : "off");
200 else {
201 _dprintf("%s: no radio change = %d\n", __FUNCTION__, radio);
203 #endif
206 #ifdef LINUX26
207 allow_fastnat("restrictions", (ipt_active == 0));
208 try_enabling_fastnat();
209 #endif
210 simple_unlock("restrictions");
211 return 0;
214 void ipt_restrictions(void)
216 char buf[8192];
217 char *p, *q;
218 int n;
219 char *comps, *matches, *http;
220 int nrule;
221 int blockall;
222 char reschain[32];
223 char devchain[32];
224 char nextchain[32];
225 int need_web;
226 char *pproto;
227 char *dir;
228 char *pport;
229 int proto;
230 char *ipp2p;
231 char *layer7;
232 char *addr_type, *addr;
233 char app[256];
234 char ports[256];
235 char iptaddr[192];
236 int http_file;
237 int ex;
238 int first;
239 int v4v6_ok;
241 need_web = 0;
242 first = 1;
243 nvram_unset("rrules_timewarn");
244 nvram_set("rrules_radio", "-1");
245 unsched_restrictions();
247 for (nrule = 0; nrule < MAX_NRULES; ++nrule) {
248 sprintf(buf, "rrule%d", nrule);
249 if ((p = nvram_get(buf)) == NULL) continue;
250 if (strlen(p) >= sizeof(buf)) continue;
251 strcpy(buf, p);
253 if ((vstrsep(buf, "|",
254 &q, // 0/1
255 &p, &p, &p, // time (ignored)
256 &comps, //
257 &matches, //
258 &http, //
259 &p // http file match
260 ) != 8) || (*q != '1')) continue;
261 http_file = atoi(p);
263 if (comps[0] == '~') {
264 // a wireless disable rule, skip
265 continue;
268 if (first) {
269 first = 0;
271 ip46t_write(":restrict - [0:0]\n");
272 #ifdef TCONFIG_IPV6
273 if (*wan6face)
274 ip6t_write("-A FORWARD -o %s -j restrict\n",
275 wan6face);
276 #endif
277 for (n = 0; n < wanfaces.count; ++n) {
278 if (*(wanfaces.iface[n].name)) {
279 ipt_write("-A FORWARD -o %s -j restrict\n",
280 wanfaces.iface[n].name);
285 sprintf(reschain, "rres%02d", nrule);
286 ip46t_write(":%s - [0:0]\n", reschain);
288 blockall = 1;
292 proto<dir<port<ipp2p<layer7[<addr_type<addr]
294 proto:
295 -1 = both tcp/udp
296 -2 = any protocol
297 else = proto #
298 dir:
299 if proto == -1,tcp,udp:
300 a = any port
301 s = src port
302 d = dst port
303 x = src or dst port
304 port:
305 port # if proto == -1,tcp,udp
306 ipp2p:
307 # = ipp2p bit
309 .* = pattern name
310 addr_type:
311 0 = any
312 1 = dest ip
313 2 = src ip
314 addr:
315 ip if addr_type == 1
318 while ((q = strsep(&matches, ">")) != NULL) {
319 n = vstrsep(q, "<", &pproto, &dir, &pport, &ipp2p, &layer7, &addr_type, &addr);
320 if (n == 5) {
321 // fixup for backward compatibility
322 addr_type = "0";
324 else if (n != 7) continue;
326 if ((*dir != 'a') && (*dir != 's') && (*dir != 'd') && (*dir != 'x')) continue;
328 // p2p, layer7
329 if (!ipt_ipp2p(ipp2p, app)) {
330 if (ipt_layer7(layer7, app) == -1) continue;
332 #ifdef TCONFIG_IPV6
333 v4v6_ok = ((*app) ? 0 : IPT_V6) | IPT_V4;
334 #else
335 v4v6_ok = IPT_V4;
336 #endif
338 // dest ip/domain address
339 if ((*addr_type == '1') || (*addr_type == '2')) {
340 v4v6_ok = ipt_addr(iptaddr, sizeof(iptaddr), addr, (*addr_type == '1') ? "dst" : "src", v4v6_ok, (v4v6_ok == IPT_V4), "restrictions", NULL);
341 if (!v4v6_ok)
342 continue;
344 else {
345 iptaddr[0] = 0;
348 blockall = 0;
350 // proto & ports
351 proto = atoi(pproto);
352 if (proto <= -2) {
353 // shortcut if any proto+any port
354 ip46t_flagged_write(v4v6_ok, "-A %s %s %s -j %s\n", reschain, iptaddr, app, chain_out_drop);
355 continue;
357 else if ((proto == 6) || (proto == 17) || (proto == -1)) {
358 if ((*dir != 'a') && (*pport)) {
359 if ((*dir == 'x') || (strchr(pport, ','))) {
360 // use multiport for multiple ports or src-or-dst type matches
361 snprintf(ports, sizeof(ports), "-m multiport --%sports %s", (*dir == 'x') ? "" : dir, pport);
363 else {
364 // else, use built-in
365 snprintf(ports, sizeof(ports), "--%sport %s", dir, pport);
368 else {
369 ports[0] = 0;
371 if (proto != 17)
372 ip46t_flagged_write(v4v6_ok, "-A %s -p tcp %s %s %s -j %s\n", reschain, ports, iptaddr, app, chain_out_drop);
373 if (proto != 6)
374 ip46t_flagged_write(v4v6_ok, "-A %s -p udp %s %s %s -j %s\n", reschain, ports, iptaddr, app, chain_out_drop);
376 else {
377 ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s %s -j %s\n", reschain, proto, iptaddr, app, chain_out_drop);
383 p = http;
384 while (*p) {
385 if ((*p == '\t') || (*p == '\r') || (*p == '\n') || (*p == '"')) *p = ' ';
386 ++p;
388 while ((n = strlen(http)) > 0) {
389 if (n >= 511) {
390 p = http + 510;
391 while ((p > http) && (*p != ' ')) --p;
392 if (p <= http) {
393 // too long
394 break;
396 *p = 0;
398 else p = NULL;
399 ip46t_write("-A %s -p tcp -m web --hore \"%s\" -j %s\n", reschain, http, chain_out_reject);
400 need_web = 1;
401 blockall = 0;
402 if (p == NULL) break;
403 http = p + 1;
408 app[0] = 0;
409 if (http_file & 1) strcat(app, ".ocx$ .cab$ ");
410 if (http_file & 2) strcpy(app, ".swf$ ");
411 if (http_file & 4) strcat(app, ".class$ .jar$");
412 if (app[0]) {
413 ip46t_write("-A %s -p tcp -m multiport --dports %s -m web --path \"%s\" -j %s\n",
414 reschain, nvram_safe_get("rrulewp"), app, chain_out_reject);
415 need_web = 1;
416 blockall = 0;
419 if (*comps) {
420 if (blockall) {
421 ip46t_write("-X %s\n", reschain); // chain not needed
422 sprintf(nextchain, "-j %s", chain_out_drop);
424 else {
425 sprintf(nextchain, "-g %s", reschain);
428 ex = 0;
429 sprintf(devchain, "rdev%02d", nrule);
430 ip46t_write(":%s - [0:0]\n", devchain);
431 while ((q = strsep(&comps, ">")) != NULL) {
432 if (*q == 0) continue;
433 if (*q == '!') {
434 ex = 1;
435 continue;
437 #ifdef TCONFIG_IPV6
438 v4v6_ok = IPT_V6 | IPT_V4;
439 #else
440 v4v6_ok = IPT_V4;
441 #endif
442 if (sscanf(q, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
443 iptaddr, iptaddr, iptaddr, iptaddr, iptaddr, iptaddr) == 6) {
444 snprintf(iptaddr, sizeof(iptaddr), "-m mac --mac-source %s", q);
446 else {
447 v4v6_ok = ipt_addr(iptaddr, sizeof(iptaddr), q, "src", v4v6_ok, (v4v6_ok == IPT_V4), "restrictions", "filtering");
448 if (!v4v6_ok)
449 continue;
451 ip46t_flagged_write(v4v6_ok,
452 "-A %s %s %s\n", devchain, iptaddr, ex ? "-j RETURN" : nextchain);
455 if (ex) {
456 ip46t_write("-A %s %s\n", devchain, nextchain);
459 else if (blockall) {
460 ip46t_write("-A %s -j %s\n", reschain, chain_out_drop);
464 nvram_set("rrules_activated", "0");
466 if (need_web)
467 #ifdef LINUX26
468 modprobe("xt_web");
469 #else
470 modprobe("ipt_web");
471 #endif