libevent: updated to 2.0.22
[tomato.git] / release / src-rt-6.x.4708 / router / rc / restrict.c
blobea07337483009ea4f80ab81b64b8dcfee3d0ae69
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 eval("cru", "d", "rcheck");
19 inline void sched_restrictions(void)
21 eval("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 eval("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);
283 // Only mess with DNS requests that are coming in on INPUT
284 ip46t_write("-I INPUT 1 ! -i lo -p udp --dport 53 -j restrict\n");
287 sprintf(reschain, "rres%02d", nrule);
288 ip46t_write(":%s - [0:0]\n", reschain);
290 blockall = 1;
292 while ((q = strsep(&matches, ">")) != NULL) {
293 n = vstrsep(q, "<", &pproto, &dir, &pport, &ipp2p, &layer7, &addr_type, &addr);
294 if (n == 5) {
295 // fixup for backward compatibility
296 addr_type = "0";
298 else if (n != 7) continue;
300 if ((*dir != 'a') && (*dir != 's') && (*dir != 'd') && (*dir != 'x')) continue;
302 // p2p, layer7
303 if (!ipt_ipp2p(ipp2p, app)) {
304 if (ipt_layer7(layer7, app) == -1) continue;
306 #ifdef TCONFIG_IPV6
307 v4v6_ok = ((*app) ? 0 : IPT_V6) | IPT_V4;
308 #else
309 v4v6_ok = IPT_V4;
310 #endif
312 // dest ip/domain address
313 if ((*addr_type == '1') || (*addr_type == '2')) {
314 v4v6_ok = ipt_addr(iptaddr, sizeof(iptaddr), addr, (*addr_type == '1') ? "dst" : "src", v4v6_ok, (v4v6_ok == IPT_V4), "restrictions", NULL);
315 if (!v4v6_ok)
316 continue;
318 else {
319 iptaddr[0] = 0;
322 blockall = 0;
324 // proto & ports
325 proto = atoi(pproto);
326 if (proto <= -2) {
327 // shortcut if any proto+any port
328 ip46t_flagged_write(v4v6_ok, "-A %s %s %s -j %s\n", reschain, iptaddr, app, chain_out_drop);
329 continue;
331 else if ((proto == 6) || (proto == 17) || (proto == -1)) {
332 if ((*dir != 'a') && (*pport)) {
333 if ((*dir == 'x') || (strchr(pport, ','))) {
334 // use multiport for multiple ports or src-or-dst type matches
335 snprintf(ports, sizeof(ports), "-m multiport --%sports %s", (*dir == 'x') ? "" : dir, pport);
337 else {
338 // else, use built-in
339 snprintf(ports, sizeof(ports), "--%sport %s", dir, pport);
342 else {
343 ports[0] = 0;
345 if (proto != 17)
346 ip46t_flagged_write(v4v6_ok, "-A %s -p tcp %s %s %s -j %s\n", reschain, ports, iptaddr, app, chain_out_drop);
347 if (proto != 6)
348 ip46t_flagged_write(v4v6_ok, "-A %s -p udp %s %s %s -j %s\n", reschain, ports, iptaddr, app, chain_out_drop);
350 else {
351 ip46t_flagged_write(v4v6_ok, "-A %s -p %d %s %s -j %s\n", reschain, proto, iptaddr, app, chain_out_drop);
357 p = http;
358 while (*p) {
359 if ((*p == '\t') || (*p == '\r') || (*p == '\n') || (*p == '"')) *p = ' ';
360 ++p;
362 while ((n = strlen(http)) > 0) {
363 if (n >= 511) {
364 p = http + 510;
365 while ((p > http) && (*p != ' ')) --p;
366 if (p <= http) {
367 // too long
368 break;
370 *p = 0;
372 else p = NULL;
373 ip46t_write("-A %s -p tcp -m web --hore \"%s\" -j %s\n", reschain, http, chain_out_reject);
374 need_web = 1;
375 blockall = 0;
376 if (p == NULL) break;
377 http = p + 1;
382 app[0] = 0;
383 if (http_file & 1) strcat(app, ".ocx$ .cab$ ");
384 if (http_file & 2) strcpy(app, ".swf$ ");
385 if (http_file & 4) strcat(app, ".class$ .jar$");
386 if (app[0]) {
387 ip46t_write("-A %s -p tcp -m multiport --dports %s -m web --path \"%s\" -j %s\n",
388 reschain, nvram_safe_get("rrulewp"), app, chain_out_reject);
389 need_web = 1;
390 blockall = 0;
393 if (*comps) {
394 if (blockall) {
395 ip46t_write("-X %s\n", reschain); // chain not needed
396 sprintf(nextchain, "-j %s", chain_out_drop);
398 else {
399 sprintf(nextchain, "-g %s", reschain);
402 ex = 0;
403 sprintf(devchain, "rdev%02d", nrule);
404 ip46t_write(":%s - [0:0]\n", devchain);
405 while ((q = strsep(&comps, ">")) != NULL) {
406 if (*q == 0) continue;
407 if (*q == '!') {
408 ex = 1;
409 continue;
411 #ifdef TCONFIG_IPV6
412 v4v6_ok = IPT_V6 | IPT_V4;
413 #else
414 v4v6_ok = IPT_V4;
415 #endif
416 if (sscanf(q, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
417 iptaddr, iptaddr, iptaddr, iptaddr, iptaddr, iptaddr) == 6) {
418 snprintf(iptaddr, sizeof(iptaddr), "-m mac --mac-source %s", q);
420 else {
421 v4v6_ok = ipt_addr(iptaddr, sizeof(iptaddr), q, "src", v4v6_ok, (v4v6_ok == IPT_V4), "restrictions", "filtering");
422 if (!v4v6_ok)
423 continue;
425 ip46t_flagged_write(v4v6_ok,
426 "-A %s %s %s\n", devchain, iptaddr, ex ? "-j RETURN" : nextchain);
429 if (ex) {
430 ip46t_write("-A %s %s\n", devchain, nextchain);
433 else if (blockall) {
434 ip46t_write("-A %s -j %s\n", reschain, chain_out_drop);
438 nvram_set("rrules_activated", "0");
440 if (need_web)
441 modprobe("ipt_web");