Tomato 1.28
[tomato.git] / release / src / router / rc / restrict.c
blob3344bb8780ca3ebab5e91571b6a6e927fa988cce
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
15 static void unsched_restrictions(void)
17 system("cru d rcheck");
20 void sched_restrictions(void)
22 system("rcheck");
25 static int in_sched(int now_mins, int now_dow, int sched_begin, int sched_end, int sched_dow)
27 // all day
28 if ((sched_begin < 0) || (sched_end < 0)) {
29 return (sched_dow & now_dow) != 0;
32 // simple min to max
33 if (sched_begin < sched_end) {
34 return (((sched_dow & now_dow) != 0) && (now_mins >= sched_begin) && (now_mins < sched_end));
37 // 15:00 - 01:00 = 15:00 Sun to 01:00 Mon
38 // 12:00 - 12:00 = 12:00 Sun to 12:00 Mon
40 if ((now_dow & sched_dow) != 0) {
41 if (now_mins >= sched_begin) return 1;
44 // ror now_dow, 1
45 if (now_dow == 1) now_dow = (1 << 6);
46 else now_dow >>= 1;
48 if ((now_dow & sched_dow) != 0) {
49 if (now_mins < sched_end) return 1;
52 // printf("now_mins=%d sched_end=%d now_dow=%d sched_dow=%d\n", now_mins, sched_end, now_dow, sched_dow);
53 return 0;
57 int rcheck_main(int argc, char *argv[])
59 char buf[256];
60 char *p;
61 int sched_begin;
62 int sched_end;
63 int sched_dow;
64 time_t now;
65 struct tm *tms;
66 int now_dow;
67 int now_mins;
68 int n;
69 int nrule;
70 char comp;
71 int insch;
72 unsigned long long activated;
73 int count;
74 int radio;
75 int r;
77 if (!nvram_contains_word("log_events", "acre")) {
78 setlogmask(LOG_MASK(LOG_EMERG)); // can't set to 0
81 simple_lock("restrictions");
83 now = time(0);
84 if (now < Y2K) {
85 if (!nvram_match("rrules_timewarn", "1")) {
86 nvram_set("rrules_timewarn", "1");
87 syslog(LOG_INFO, "Time not yet set. Only \"all day, everyday\" restrictions will be activated.");
89 now_mins = now_dow = 0;
91 else {
92 tms = localtime(&now);
93 now_dow = 1 << tms->tm_wday;
94 now_mins = (tms->tm_hour * 60) + tms->tm_min;
97 activated = strtoull(nvram_safe_get("rrules_activated"), NULL, 16);
98 count = 0;
99 radio = nvram_match("wl_radio", "1") ? -1 : -2;
100 for (nrule = 0; nrule < MAX_NRULES; ++nrule) {
101 sprintf(buf, "rrule%d", nrule);
102 if ((p = nvram_get(buf)) == NULL) continue;
103 if (sscanf(p, "%d|%d|%d|%d|%c", &n, &sched_begin, &sched_end, &sched_dow, &comp) != 5) continue;
104 if (n == 0) continue;
106 ++count;
108 if (now < Y2K) {
109 if ((sched_begin >= 0) || (sched_end >= 0) || (sched_dow != 0x7F)) continue;
110 insch = 1;
112 else {
113 insch = in_sched(now_mins, now_dow, sched_begin, sched_end, sched_dow);
116 n = 1 << nrule;
117 if ((insch) == ((activated & n) != 0)) {
118 continue;
121 syslog(LOG_INFO, "%sctivating rule %d", insch ? "A" : "Dea", nrule);
123 if (comp == '~') {
124 if ((radio != 0) && (radio != -2)) radio = !insch;
126 else {
127 sprintf(buf, "r%s%02d", (comp != '|') ? "dev" : "res", nrule);
129 r = eval("iptables", "-D", "restrict", "-j", buf);
130 if (insch) {
131 // ignore error above (if any)
133 r = eval("iptables", "-A", "restrict", "-j", buf);
136 if (r != 0) {
137 syslog(LOG_ERR, "Iptables command failed. Retrying in 15 minutes.");
138 continue;
141 if (eval("iptables", insch ? "-A" : "-D", "restrict", "-j", buf) != 0) {
142 syslog(LOG_ERR, "iptables command failed");
143 continue;
148 if (insch) activated |= n;
149 else activated &= ~n;
152 sprintf(buf, "%llx", activated);
153 nvram_set("rrules_activated", buf);
155 if (count > 0) {
156 if ((argc != 2) || (strcmp(argv[1], "--cron") != 0)) {
157 system("cru a rcheck '*/15 * * * * rcheck --cron'");
160 else {
161 unsched_restrictions();
164 if (radio >= 0) {
165 nvram_set("rrules_radio", radio ? "0" : "1");
166 if (get_radio() != radio) {
167 _dprintf("%s: radio = %d\n", __FUNCTION__, radio);
168 eval("radio", radio ? "on" : "off");
170 else {
171 _dprintf("%s: no radio change = %d\n", __FUNCTION__, radio);
175 simple_unlock("restrictions");
176 return 0;
179 void ipt_restrictions(void)
181 char buf[8192];
182 char *p, *q;
183 int n;
184 char *comps, *matches, *http;
185 int nrule;
186 int blockall;
187 char reschain[32];
188 char devchain[32];
189 char nextchain[32];
190 int need_web;
191 char *pproto;
192 char *dir;
193 char *pport;
194 int proto;
195 char *ipp2p;
196 char *layer7;
197 char app[256];
198 char ports[256];
199 int http_file;
200 int ex;
201 int first;
203 need_web = 0;
204 first = 1;
205 nvram_unset("rrules_timewarn");
206 nvram_set("rrules_radio", "-1");
207 unsched_restrictions();
209 for (nrule = 0; nrule < MAX_NRULES; ++nrule) {
210 sprintf(buf, "rrule%d", nrule);
211 if ((p = nvram_get(buf)) == NULL) continue;
212 if (strlen(p) >= sizeof(buf)) continue;
213 strcpy(buf, p);
215 if ((vstrsep(buf, "|",
216 &q, // 0/1
217 &p, &p, &p, // time (ignored)
218 &comps, //
219 &matches, //
220 &http, //
221 &p // http file match
222 ) != 8) || (*q != '1')) continue;
223 http_file = atoi(p);
225 if (comps[0] == '~') {
226 // a wireless disable rule, skip
227 continue;
230 if (first) {
231 first = 0;
232 ipt_write(":restrict - [0:0]\n"
233 "-A FORWARD -o %s -j restrict\n", wanface);
236 sprintf(reschain, "rres%02d", nrule);
237 ipt_write(":%s - [0:0]\n", reschain);
239 blockall = 1;
243 proto<dir<port<ipp2p<layer7
245 proto:
246 -1 = both tcp/udp
247 else = proto #
248 dir:
249 a = any port
250 s = src port
251 d = dst port
252 x = src or dst port
253 ipp2p:
254 # = ipp2p bit
256 .* = pattern name
259 while ((q = strsep(&matches, ">")) != NULL) {
260 if (vstrsep(q, "<", &pproto, &dir, &pport, &ipp2p, &layer7) != 5) continue;
262 if ((*dir != 'a') && (*dir != 's') && (*dir != 'd') && (*dir != 'x')) continue;
263 if ((*dir != 'a') && (*pport)) {
264 if ((*dir == 'x') || (strchr(pport, ','))) {
265 // use mport for multiple ports or src-or-dst type matches
266 snprintf(ports, sizeof(ports), "-m mport --%sports %s", (*dir == 'x') ? "" : dir, pport);
268 else {
269 // else, use built-in
270 snprintf(ports, sizeof(ports), "--%sport %s", dir, pport);
273 else {
274 ports[0] = 0;
277 if (!ipt_ipp2p(ipp2p, app)) {
278 if (ipt_layer7(layer7, app) == -1) continue;
281 blockall = 0;
283 proto = atoi(pproto);
284 if ((*dir == 'a') && (proto == -1)) {
285 // shortcut if tcp+udp+any port
286 ipt_write("-A %s %s -j %s\n", reschain, app, chain_out_drop);
287 continue;
290 if (proto != 17)
291 ipt_write("-A %s -p %sp %s %s -j %s\n", reschain, "tc", ports, app, chain_out_drop);
292 if (proto != 6)
293 ipt_write("-A %s -p %sp %s %s -j %s\n", reschain, "ud", ports, app, chain_out_drop);
298 p = http;
299 while (*p) {
300 if ((*p == '\t') || (*p == '\r') || (*p == '\n') || (*p == '"')) *p = ' ';
301 ++p;
303 while ((n = strlen(http)) > 0) {
304 if (n >= 511) {
305 p = http + 510;
306 while ((p > http) && (*p != ' ')) --p;
307 if (p <= http) {
308 // too long
309 break;
311 *p = 0;
313 else p = NULL;
314 ipt_write("-A %s -p tcp -m web --hore \"%s\" -j %s\n", reschain, http, chain_out_reject);
315 need_web = 1;
316 blockall = 0;
317 if (p == NULL) break;
318 http = p + 1;
323 app[0] = 0;
324 if (http_file & 1) strcat(app, ".ocx$ .cab$ ");
325 if (http_file & 2) strcpy(app, ".swf$ ");
326 if (http_file & 4) strcat(app, ".class$ .jar$");
327 if (app[0]) {
328 ipt_write("-A %s -p tcp -m mport --dports %s -m web --path \"%s\" -j %s\n",
329 reschain, nvram_safe_get("rrulewp"), app, chain_out_reject);
330 need_web = 1;
331 blockall = 0;
334 if (*comps) {
335 if (blockall) {
336 ipt_write("-X %s\n", reschain); // chain not needed
337 sprintf(nextchain, "-j %s", chain_out_drop);
339 else {
340 sprintf(nextchain, "-g %s", reschain);
343 ex = 0;
344 sprintf(devchain, "rdev%02d", nrule);
345 ipt_write(":%s - [0:0]\n", devchain);
346 while ((q = strsep(&comps, ">")) != NULL) {
347 if (*q == 0) continue;
348 if (*q == '!') {
349 ex = 1;
350 continue;
352 if (strchr(q, ':')) {
353 p = "-m mac --mac-source";
355 else if (strchr(q, '-')) {
356 p = "-m iprange --src-range";
358 else {
359 p = "-s";
361 ipt_write("-A %s %s %s %s\n", devchain, p, q, ex ? "-j RETURN" : nextchain);
364 if (ex) {
365 ipt_write("-A %s %s\n", devchain, nextchain);
368 else if (blockall) {
369 ipt_write("-A %s -j %s\n", reschain, chain_out_drop);
373 nvram_set("rrules_activated", "0");
375 if (need_web) modprobe("ipt_web");