Remove TomatoAnon
[tomato.git] / release / src / router / httpd / ctnf.c
blob48550d10199c50d0bbe8b439bf94b8b37fc09ba2
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "tomato.h"
10 #include <ctype.h>
11 #include <sys/sysinfo.h>
12 #include <sys/stat.h>
13 #include <sys/ioctl.h>
14 #include <net/if.h>
15 #include <fcntl.h>
16 #include <netinet/in.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
20 #include <time.h>
21 #include <dirent.h>
23 #define IP6_PREFIX_NOT_MATCH( a, b, bits ) (memcmp(&a.s6_addr[0], &b.s6_addr[0], bits/8) != 0 || ( bits % 8 && (a.s6_addr[bits/8] ^ b.s6_addr[bits/8]) >> (8-(bits % 8)) ))
26 void ctvbuf(FILE *f) {
27 int n;
28 struct sysinfo si;
29 // meminfo_t mem;
31 #if 1
32 const char *p;
34 if ((p = nvram_get("ct_max")) != NULL) {
35 n = atoi(p);
36 if (n == 0) n = 2048;
37 else if (n < 1024) n = 1024;
38 else if (n > 10240) n = 10240;
40 else {
41 n = 2048;
43 #else
44 char s[64];
46 if (f_read_string("/proc/sys/net/ipv4/ip_conntrack_max", s, sizeof(s)) > 0) n = atoi(s);
47 else n = 1024;
48 if (n < 1024) n = 1024;
49 else if (n > 10240) n = 10240;
50 #endif
52 n *= 170; // avg tested
54 // get_memory(&mem);
55 // if (mem.maxfreeram < (n + (64 * 1024))) n = mem.maxfreeram - (64 * 1024);
57 sysinfo(&si);
58 if (si.freeram < (n + (64 * 1024))) n = si.freeram - (64 * 1024);
60 // cprintf("free: %dK, buffer: %dK\n", si.freeram / 1024, n / 1024);
62 if (n > 4096) {
63 // n =
64 setvbuf(f, NULL, _IOFBF, n);
65 // cprintf("setvbuf = %d\n", n);
69 void asp_ctcount(int argc, char **argv)
71 static const char *states[10] = {
72 "NONE", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT",
73 "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN" };
74 int count[13]; // tcp(10) + udp(2) + total(1) = 13 / max classes = 10
75 FILE *f;
76 char s[512];
77 char *p;
78 char *t;
79 int i;
80 int n;
81 int mode;
82 unsigned long rip;
83 unsigned long lan;
84 unsigned long mask;
86 if (argc != 1) return;
88 #if defined(TCONFIG_IPV6) && defined(LINUX26)
89 char src[INET6_ADDRSTRLEN];
90 char dst[INET6_ADDRSTRLEN];
91 struct in6_addr rip6;
92 struct in6_addr lan6;
93 struct in6_addr in6;
94 int lan6_prefix_len;
96 lan6_prefix_len = nvram_get_int("ipv6_prefix_length");
97 if (ipv6_enabled()) {
98 inet_pton(AF_INET6, nvram_safe_get("ipv6_prefix"), &lan6);
99 ipv6_router_address(&rip6);
101 #endif
103 mode = atoi(argv[0]);
105 memset(count, 0, sizeof(count));
107 #if defined(TCONFIG_IPV6) && defined(LINUX26)
108 if ((f = fopen("/proc/net/nf_conntrack", "r")) != NULL) {
109 #else
110 if ((f = fopen("/proc/net/ip_conntrack", "r")) != NULL) {
111 #endif
112 ctvbuf(f); // if possible, read in one go
114 if (nvram_match("t_hidelr", "1")) {
115 mask = inet_addr(nvram_safe_get("lan_netmask"));
116 rip = inet_addr(nvram_safe_get("lan_ipaddr"));
117 lan = rip & mask;
119 else {
120 rip = lan = mask = 0;
123 while (fgets(s, sizeof(s), f)) {
124 #if defined(TCONFIG_IPV6) && defined(LINUX26)
125 if (strncmp(s, "ipv4", 4) == 0) {
126 t = s + 11;
127 #else
128 t = s;
129 #endif
130 if (rip != 0) {
132 // src=x.x.x.x dst=x.x.x.x // DIR_ORIGINAL
133 if ((p = strstr(t + 14, "src=")) == NULL) continue;
134 if ((inet_addr(p + 4) & mask) == lan) {
135 if ((p = strstr(p + 13, "dst=")) == NULL) continue;
136 if (inet_addr(p + 4) == rip) continue;
139 #if defined(TCONFIG_IPV6) && defined(LINUX26)
141 else if (strncmp(s, "ipv6", 4) == 0) {
142 t = s + 12;
144 if (rip != 0) {
145 if ((p = strstr(t + 14, "src=")) == NULL) continue;
146 if (sscanf(p, "src=%s dst=%s", src, dst) != 2) continue;
148 if (inet_pton(AF_INET6, src, &in6) <= 0) continue;
149 inet_ntop(AF_INET6, &in6, src, sizeof(src));
151 if (!IP6_PREFIX_NOT_MATCH(lan6, in6, lan6_prefix_len)) continue;
154 else {
155 continue; // another proto family?!
157 #endif
159 if (mode == 0) {
160 // count connections per state
161 if (strncmp(t, "tcp", 3) == 0) {
162 for (i = 9; i >= 0; --i) {
163 if (strstr(s, states[i]) != NULL) {
164 count[i]++;
165 break;
169 else if (strncmp(t, "udp", 3) == 0) {
170 if (strstr(s, "[ASSURED]") != NULL) {
171 count[11]++;
173 else {
174 count[10]++;
177 count[12]++;
179 else {
180 // count connections per mark
181 if ((p = strstr(s, " mark=")) != NULL) {
182 n = atoi(p + 6) & 0xFF;
183 if (n <= 10) count[n]++;
188 fclose(f);
191 if (mode == 0) {
192 p = s;
193 for (i = 0; i < 12; ++i) {
194 p += sprintf(p, ",%d", count[i]);
196 web_printf("\nconntrack = [%d%s];\n", count[12], s);
198 else {
199 p = s;
200 for (i = 1; i < 11; ++i) {
201 p += sprintf(p, ",%d", count[i]);
203 web_printf("\nnfmarks = [%d%s];\n", count[0], s);
207 void asp_ctdump(int argc, char **argv)
209 FILE *f;
210 char s[512];
211 char *p, *q;
212 int x;
213 int mark;
214 int rule;
215 int findmark;
216 unsigned int proto;
217 unsigned int time;
218 #if defined(TCONFIG_IPV6) && defined(LINUX26)
219 unsigned int family;
220 char src[INET6_ADDRSTRLEN];
221 char dst[INET6_ADDRSTRLEN];
222 #else
223 const unsigned int family = 2;
224 char src[INET_ADDRSTRLEN];
225 char dst[INET_ADDRSTRLEN];
226 #endif
227 char sport[16];
228 char dport[16];
229 char byteso[16];
230 char bytesi[16];
231 int dir_reply;
233 unsigned long rip;
234 unsigned long lan;
235 unsigned long mask;
236 char comma;
238 if (argc != 1) return;
240 findmark = atoi(argv[0]);
242 mask = inet_addr(nvram_safe_get("lan_netmask"));
243 rip = inet_addr(nvram_safe_get("lan_ipaddr"));
244 lan = rip & mask;
246 #if defined(TCONFIG_IPV6) && defined(LINUX26)
247 struct in6_addr rip6;
248 struct in6_addr lan6;
249 struct in6_addr in6;
250 int lan6_prefix_len;
252 lan6_prefix_len = nvram_get_int("ipv6_prefix_length");
253 if (ipv6_enabled()) {
254 inet_pton(AF_INET6, nvram_safe_get("ipv6_prefix"), &lan6);
255 ipv6_router_address(&rip6);
257 #endif
259 if (nvram_match("t_hidelr", "0")) rip = 0; // hide lan -> router?
263 /proc/net/nf_conntrack prefix (compared to ip_conntrack):
264 "ipvx" + 5 spaces + "2" or "10" + 1 space
266 add bytes out/in to table
270 web_puts("\nctdump = [");
271 comma = ' ';
272 #if defined(TCONFIG_IPV6) && defined(LINUX26)
273 if ((f = fopen("/proc/net/nf_conntrack", "r")) != NULL) {
274 #else
275 if ((f = fopen("/proc/net/ip_conntrack", "r")) != NULL) {
276 #endif
277 ctvbuf(f);
278 while (fgets(s, sizeof(s), f)) {
279 dir_reply = 0;
280 if ((p = strstr(s, " mark=")) == NULL) continue;
281 mark = atoi(p + 6);
282 rule = (mark >> 20) & 0xFF;
283 if ((mark &= 0xFF) > 10) mark = 0;
284 if ((findmark != -1) && (mark != findmark)) continue;
285 #if defined(TCONFIG_IPV6) && defined(LINUX26)
286 if (sscanf(s, "%*s %u %*s %u %u", &family, &proto, &time) != 3) continue;
287 if ((p = strstr(s + 25, "src=")) == NULL) continue;
288 #else
289 if (sscanf(s, "%*s %u %u", &proto, &time) != 2) continue;
290 if ((p = strstr(s + 14, "src=")) == NULL) continue;
291 #endif
292 if (sscanf(p, "src=%s dst=%s %n", src, dst, &x) != 2) continue;
293 p += x;
295 if ((proto == 6) || (proto == 17)) {
296 if (sscanf(p, "sport=%s dport=%s %*s bytes=%s %n", sport, dport, byteso, &x) != 3) continue;
297 p += x;
298 if ((q = strstr(p, "bytes=")) == NULL) continue;
299 if (sscanf(q, "bytes=%s", bytesi) != 1) continue;
301 else {
302 sport[0] = 0;
303 dport[0] = 0;
304 byteso[0] = 0;
305 bytesi[0] = 0;
308 switch (family) {
309 case 2:
310 if ((inet_addr(src) & mask) != lan) {
311 dir_reply = 1;
312 // de-nat
313 if ((p = strstr(p, "src=")) == NULL) continue;
314 if ((proto == 6) || (proto == 17)) {
315 if (sscanf(p, "src=%s dst=%s sport=%s dport=%s", dst, src, dport, sport) != 4) continue; // intentionally backwards
317 else {
318 if (sscanf(p, "src=%s dst=%s", dst, src) != 2) continue;
321 else if (rip != 0 && inet_addr(dst) == rip) continue;
322 break;
323 #if defined(TCONFIG_IPV6) && defined(LINUX26)
324 case 10:
325 if (inet_pton(AF_INET6, src, &in6) <= 0) continue;
326 inet_ntop(AF_INET6, &in6, src, sizeof(src));
328 if (IP6_PREFIX_NOT_MATCH(lan6, in6, lan6_prefix_len))
329 dir_reply = 1;
331 if (inet_pton(AF_INET6, dst, &in6) <= 0) continue;
332 inet_ntop(AF_INET6, &in6, dst, sizeof(dst));
334 if (dir_reply == 0 && rip != 0 && (IN6_ARE_ADDR_EQUAL(&rip6, &in6)))
335 continue;
336 break;
337 #endif
340 if (dir_reply == 1) {
341 web_printf("%c[%u,%u,'%s','%s','%s','%s','%s','%s',%d,%d]", comma, proto, time, dst, src, dport, sport, bytesi, byteso, mark, rule );
343 else {
344 web_printf("%c[%u,%u,'%s','%s','%s','%s','%s','%s',%d,%d]", comma, proto, time, src, dst, sport, dport, byteso, bytesi, mark, rule );
346 comma = ',';
349 web_puts("];\n");
352 void asp_ctrate(int argc, char **argv)
354 unsigned int a_time, a_proto;
355 unsigned int a_bytes_o, a_bytes_i;
356 char a_sport[16];
357 char a_dport[16];
359 char *p, *q;
360 int x;
361 int len;
363 #if defined(TCONFIG_IPV6) && defined(LINUX26)
364 unsigned int a_fam, b_fam;
365 char a_src[INET6_ADDRSTRLEN];
366 char a_dst[INET6_ADDRSTRLEN];
367 #else
368 const unsigned int a_fam = 2;
369 char a_src[INET_ADDRSTRLEN];
370 char a_dst[INET_ADDRSTRLEN];
371 #endif
373 unsigned int b_time, b_proto;
374 unsigned int b_bytes_o, b_bytes_i;
376 char sa[512];
377 char sb[512];
379 FILE *a;
380 FILE *b;
382 long b_pos;
384 int delay;
385 int thres;
387 long outbytes;
388 long inbytes;
389 int n;
390 char comma;
392 int dir_reply;
394 unsigned long rip;
395 unsigned long lan;
396 unsigned long mask;
398 mask = inet_addr(nvram_safe_get("lan_netmask"));
399 rip = inet_addr(nvram_safe_get("lan_ipaddr"));
400 lan = rip & mask;
402 #if defined(TCONFIG_IPV6) && defined(LINUX26)
403 struct in6_addr rip6;
404 struct in6_addr lan6;
405 struct in6_addr in6;
406 int lan6_prefix_len;
408 lan6_prefix_len = nvram_get_int("ipv6_prefix_length");
409 if (ipv6_enabled()) {
410 inet_pton(AF_INET6, nvram_safe_get("ipv6_prefix"), &lan6);
411 ipv6_router_address(&rip6);
413 #endif
415 if (nvram_match("t_hidelr", "0")) rip = 0; // hide lan -> router?
417 web_puts("\nctrate = [");
418 comma = ' ';
420 #if defined(TCONFIG_IPV6) && defined(LINUX26)
421 const char name[] = "/proc/net/nf_conntrack";
422 #else
423 const char name[] = "/proc/net/ip_conntrack";
424 #endif
426 if (argc != 2) return;
428 delay = atoi(argv[0]);
429 thres = atoi(argv[1]) * delay;
431 if ((a = fopen(name, "r")) == NULL) return;
432 if ((b = tmpfile()) == NULL) return;
434 size_t count;
435 char *buffer;
437 buffer=(char *)malloc(1024);
439 while (!feof(a)) {
440 count = fread(buffer, 1, 1024, a);
441 fwrite(buffer, 1, count, b);
444 rewind(b);
445 rewind(a);
447 usleep(1000000 * (int)delay);
449 #define MAX_SEARCH 10
451 // a = current, b = previous
452 while (fgets(sa, sizeof(sa), a)) {
453 #if defined(TCONFIG_IPV6) && defined(LINUX26)
454 if (sscanf(sa, "%*s %u %*s %u %u", &a_fam, &a_proto, &a_time) != 3) continue;
455 #else
456 if (sscanf(sa, "%*s %u %u", &a_proto, &a_time) != 2) continue;
457 #endif
458 if ((a_proto != 6) && (a_proto != 17)) continue;
459 if ((p = strstr(sa, "src=")) == NULL) continue;
461 if (sscanf(p, "src=%s dst=%s sport=%s dport=%s%n %*s bytes=%u %n", a_src, a_dst, a_sport, a_dport, &len, &a_bytes_o, &x) != 5) continue;
463 if ((q = strstr(p+x, "bytes=")) == NULL) continue;
464 if (sscanf(q, "bytes=%u", &a_bytes_i) != 1) continue;
466 dir_reply = 0;
468 switch(a_fam) {
469 case 2:
470 if ((inet_addr(a_src) & mask) != lan) dir_reply = 1;
471 else if (rip != 0 && inet_addr(a_dst) == rip) continue;
472 break;
473 #if defined(TCONFIG_IPV6) && defined(LINUX26)
474 case 10:
475 if (inet_pton(AF_INET6, a_src, &in6) <= 0) continue;
476 inet_ntop(AF_INET6, &in6, a_src, sizeof(a_src));
478 if (IP6_PREFIX_NOT_MATCH(lan6, in6, lan6_prefix_len))
479 dir_reply = 1;
481 if (inet_pton(AF_INET6, a_dst, &in6) <= 0) continue;
482 inet_ntop(AF_INET6, &in6, a_dst, sizeof(a_dst));
484 if (dir_reply == 0 && rip != 0 && (IN6_ARE_ADDR_EQUAL(&rip6, &in6)))
485 continue;
486 break;
487 default:
488 continue;
489 #endif
492 b_pos = ftell(b);
493 n = 0;
494 while (fgets(sb, sizeof(sb), b) && ++n < MAX_SEARCH) {
495 #if defined(TCONFIG_IPV6) && defined(LINUX26)
496 if (sscanf(sb, "%*s %u %*s %u %u", &b_fam, &b_proto, &b_time) != 3) continue;
497 if ((b_fam != a_fam)) continue;
498 #else
499 if (sscanf(sb, "%*s %u %u", &b_proto, &b_time) != 2) continue;
500 #endif
501 if ((b_proto != a_proto)) continue;
502 if ((q = strstr(sb, "src=")) == NULL) continue;
504 if (strncmp(p, q, (size_t)len)) continue;
506 // Ok, they should be the same now. Grab the byte counts.
507 if ((q = strstr(q+len, "bytes=")) == NULL) continue;
508 if (sscanf(q, "bytes=%u", &b_bytes_o) != 1) continue;
510 if ((q = strstr(q+len, "bytes=")) == NULL) continue;
511 if (sscanf(q, "bytes=%u", &b_bytes_i) != 1) continue;
513 break;
516 if (feof(b) || n >= MAX_SEARCH) {
517 // Assume this is a new connection
518 b_bytes_o = 0;
519 b_bytes_i = 0;
520 b_time = 0;
522 // Reset the search so we don't miss anything
523 fseek(b, b_pos, SEEK_SET);
524 n = -n;
527 outbytes = ((long)a_bytes_o - (long)b_bytes_o);
528 inbytes = ((long)a_bytes_i - (long)b_bytes_i);
530 if ((outbytes < thres) && (inbytes < thres)) continue;
532 if (dir_reply == 1 && a_fam == 2) {
533 // de-nat
534 if ((q = strstr(p+x, "src=")) == NULL) continue;
535 if (sscanf(q, "src=%s dst=%s sport=%s dport=%s", a_dst, a_src, a_dport, a_sport) != 4) continue;
538 if (dir_reply == 1) {
539 web_printf("%c[%u,'%s','%s','%s','%s',%li,%li]",
540 comma, a_proto, a_dst, a_src, a_dport, a_sport, inbytes, outbytes );
542 else {
543 web_printf("%c[%u,'%s','%s','%s','%s',%li,%li]",
544 comma, a_proto, a_src, a_dst, a_sport, a_dport, outbytes, inbytes );
546 comma = ',';
548 web_puts("];\n");
550 fclose(a);
551 fclose(b);
554 static void retrieveRatesFromTc(const char* deviceName, unsigned long ratesArray[])
556 char s[256];
557 FILE *f;
558 unsigned long u;
559 char *e;
560 int n;
562 sprintf(s, "tc -s class ls dev %s", deviceName);
563 if ((f = popen(s, "r")) != NULL) {
564 n = 1;
565 while (fgets(s, sizeof(s), f)) {
566 if (strncmp(s, "class htb 1:", 12) == 0) {
567 n = atoi(s + 12);
569 else if (strncmp(s, " rate ", 6) == 0) {
570 if ((n % 10) == 0) {
571 n /= 10;
572 if ((n >= 1) && (n <= 10)) {
573 u = strtoul(s + 6, &e, 10);
574 if (*e == 'K') u *= 1000;
575 else if (*e == 'M') u *= 1000 * 1000;
576 ratesArray[n - 1] = u;
577 n = 1;
582 pclose(f);
586 void asp_qrate(int argc, char **argv)
588 unsigned long rates[10];
589 int n;
590 char comma;
591 char *a[1];
593 a[0] = "1";
594 asp_ctcount(1, a);
596 memset(rates, 0, sizeof(rates));
597 retrieveRatesFromTc(get_wanface(), rates);
599 comma = ' ';
600 web_puts("\nqrates_out = [0,");
601 for (n = 0; n < 10; ++n) {
602 web_printf("%c%lu", comma, rates[n]);
603 comma = ',';
605 web_puts("];");
607 memset(rates, 0, sizeof(rates));
608 retrieveRatesFromTc("imq0", rates);
610 comma = ' ';
611 web_puts("\nqrates_in = [0,");
612 for (n = 0; n < 10; ++n) {
613 web_printf("%c%lu", comma, rates[n]);
614 comma = ',';
616 web_puts("];");
619 static void layer7_list(const char *path, int *first)
621 DIR *dir;
622 struct dirent *de;
623 char *p;
624 char name[NAME_MAX];
626 if ((dir = opendir(path)) != NULL) {
627 while ((de = readdir(dir)) != NULL) {
628 strlcpy(name, de->d_name, sizeof(name));
629 if ((p = strstr(name, ".pat")) == NULL) continue;
630 *p = 0;
631 web_printf("%s'%s'", *first ? "" : ",", name);
632 *first = 0;
634 closedir(dir);
638 void asp_layer7(int argc, char **argv)
640 int first = 1;
641 web_puts("\nlayer7 = [");
642 layer7_list("/etc/l7-extra", &first);
643 layer7_list("/etc/l7-protocols", &first);
644 web_puts("];\n");
647 void wo_expct(char *url)
649 f_write_string("/proc/net/expire_early", "15", 0, 0);