Changes to update Tomato RAF.
[tomato.git] / release / src / router / httpd / ctnf.c
blob32bb98af1eeb04e45f020184de9adf5debfb631d
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 #ifdef LINUX26
435 size_t count;
436 char *buffer;
438 if ((buffer=(char *)malloc(1024)) == NULL) {
439 // can't allocate memory? clean-up and exit
440 web_puts("];\n");
441 fclose(a);
442 fclose(b);
443 return;
446 while (!feof(a)) {
447 count = fread(buffer, 1, 1024, a);
448 fwrite(buffer, 1, count, b);
450 // release/deallocate buffer
451 free(buffer);
452 #else
453 while (fgets(sa, sizeof(sa), a)) {
454 fputs(sa,b);
456 #endif
458 rewind(b);
459 rewind(a);
461 usleep(1000000 * (int)delay);
463 #define MAX_SEARCH 10
465 // a = current, b = previous
466 while (fgets(sa, sizeof(sa), a)) {
467 #if defined(TCONFIG_IPV6) && defined(LINUX26)
468 if (sscanf(sa, "%*s %u %*s %u %u", &a_fam, &a_proto, &a_time) != 3) continue;
469 #else
470 if (sscanf(sa, "%*s %u %u", &a_proto, &a_time) != 2) continue;
471 #endif
472 if ((a_proto != 6) && (a_proto != 17)) continue;
473 if ((p = strstr(sa, "src=")) == NULL) continue;
475 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;
477 if ((q = strstr(p+x, "bytes=")) == NULL) continue;
478 if (sscanf(q, "bytes=%u", &a_bytes_i) != 1) continue;
480 dir_reply = 0;
482 switch(a_fam) {
483 case 2:
484 if ((inet_addr(a_src) & mask) != lan) dir_reply = 1;
485 else if (rip != 0 && inet_addr(a_dst) == rip) continue;
486 break;
487 #if defined(TCONFIG_IPV6) && defined(LINUX26)
488 case 10:
489 if (inet_pton(AF_INET6, a_src, &in6) <= 0) continue;
490 inet_ntop(AF_INET6, &in6, a_src, sizeof(a_src));
492 if (IP6_PREFIX_NOT_MATCH(lan6, in6, lan6_prefix_len))
493 dir_reply = 1;
495 if (inet_pton(AF_INET6, a_dst, &in6) <= 0) continue;
496 inet_ntop(AF_INET6, &in6, a_dst, sizeof(a_dst));
498 if (dir_reply == 0 && rip != 0 && (IN6_ARE_ADDR_EQUAL(&rip6, &in6)))
499 continue;
500 break;
501 default:
502 continue;
503 #endif
506 b_pos = ftell(b);
507 n = 0;
508 while (fgets(sb, sizeof(sb), b) && ++n < MAX_SEARCH) {
509 #if defined(TCONFIG_IPV6) && defined(LINUX26)
510 if (sscanf(sb, "%*s %u %*s %u %u", &b_fam, &b_proto, &b_time) != 3) continue;
511 if ((b_fam != a_fam)) continue;
512 #else
513 if (sscanf(sb, "%*s %u %u", &b_proto, &b_time) != 2) continue;
514 #endif
515 if ((b_proto != a_proto)) continue;
516 if ((q = strstr(sb, "src=")) == NULL) continue;
518 if (strncmp(p, q, (size_t)len)) continue;
520 // Ok, they should be the same now. Grab the byte counts.
521 if ((q = strstr(q+len, "bytes=")) == NULL) continue;
522 if (sscanf(q, "bytes=%u", &b_bytes_o) != 1) continue;
524 if ((q = strstr(q+len, "bytes=")) == NULL) continue;
525 if (sscanf(q, "bytes=%u", &b_bytes_i) != 1) continue;
527 break;
530 if (feof(b) || n >= MAX_SEARCH) {
531 // Assume this is a new connection
532 b_bytes_o = 0;
533 b_bytes_i = 0;
534 b_time = 0;
536 // Reset the search so we don't miss anything
537 fseek(b, b_pos, SEEK_SET);
538 n = -n;
541 outbytes = ((long)a_bytes_o - (long)b_bytes_o);
542 inbytes = ((long)a_bytes_i - (long)b_bytes_i);
544 if ((outbytes < thres) && (inbytes < thres)) continue;
546 if (dir_reply == 1 && a_fam == 2) {
547 // de-nat
548 if ((q = strstr(p+x, "src=")) == NULL) continue;
549 if (sscanf(q, "src=%s dst=%s sport=%s dport=%s", a_dst, a_src, a_dport, a_sport) != 4) continue;
552 if (dir_reply == 1) {
553 web_printf("%c[%u,'%s','%s','%s','%s',%li,%li]",
554 comma, a_proto, a_dst, a_src, a_dport, a_sport, inbytes, outbytes );
556 else {
557 web_printf("%c[%u,'%s','%s','%s','%s',%li,%li]",
558 comma, a_proto, a_src, a_dst, a_sport, a_dport, outbytes, inbytes );
560 comma = ',';
562 web_puts("];\n");
564 fclose(a);
565 fclose(b);
568 static void retrieveRatesFromTc(const char* deviceName, unsigned long ratesArray[])
570 char s[256];
571 FILE *f;
572 unsigned long u;
573 char *e;
574 int n;
576 sprintf(s, "tc -s class ls dev %s", deviceName);
577 if ((f = popen(s, "r")) != NULL) {
578 n = 1;
579 while (fgets(s, sizeof(s), f)) {
580 if (strncmp(s, "class htb 1:", 12) == 0) {
581 n = atoi(s + 12);
583 else if (strncmp(s, " rate ", 6) == 0) {
584 if ((n % 10) == 0) {
585 n /= 10;
586 if ((n >= 1) && (n <= 10)) {
587 u = strtoul(s + 6, &e, 10);
588 if (*e == 'K') u *= 1000;
589 else if (*e == 'M') u *= 1000 * 1000;
590 ratesArray[n - 1] = u;
591 n = 1;
596 pclose(f);
600 void asp_qrate(int argc, char **argv)
602 unsigned long rates[10];
603 int n;
604 char comma;
605 char *a[1];
607 a[0] = "1";
608 asp_ctcount(1, a);
610 memset(rates, 0, sizeof(rates));
611 retrieveRatesFromTc(get_wanface(), rates);
613 comma = ' ';
614 web_puts("\nqrates_out = [0,");
615 for (n = 0; n < 10; ++n) {
616 web_printf("%c%lu", comma, rates[n]);
617 comma = ',';
619 web_puts("];");
621 memset(rates, 0, sizeof(rates));
622 retrieveRatesFromTc("imq0", rates);
624 comma = ' ';
625 web_puts("\nqrates_in = [0,");
626 for (n = 0; n < 10; ++n) {
627 web_printf("%c%lu", comma, rates[n]);
628 comma = ',';
630 web_puts("];");
633 static void layer7_list(const char *path, int *first)
635 DIR *dir;
636 struct dirent *de;
637 char *p;
638 char name[NAME_MAX];
640 if ((dir = opendir(path)) != NULL) {
641 while ((de = readdir(dir)) != NULL) {
642 strlcpy(name, de->d_name, sizeof(name));
643 if ((p = strstr(name, ".pat")) == NULL) continue;
644 *p = 0;
645 web_printf("%s'%s'", *first ? "" : ",", name);
646 *first = 0;
648 closedir(dir);
652 void asp_layer7(int argc, char **argv)
654 int first = 1;
655 web_puts("\nlayer7 = [");
656 layer7_list("/etc/l7-extra", &first);
657 layer7_list("/etc/l7-protocols", &first);
658 web_puts("];\n");
661 void wo_expct(char *url)
663 f_write_string("/proc/net/expire_early", "15", 0, 0);