4 Copyright (C) 2006-2009 Jonathan Zarate
11 #include <sys/sysinfo.h>
13 #include <sys/ioctl.h>
16 #include <netinet/in.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.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
) {
34 if ((p
= nvram_get("ct_max")) != NULL
) {
37 else if (n
< 1024) n
= 1024;
38 else if (n
> 10240) n
= 10240;
46 if (f_read_string("/proc/sys/net/ipv4/ip_conntrack_max", s
, sizeof(s
)) > 0) n
= atoi(s
);
48 if (n
< 1024) n
= 1024;
49 else if (n
> 10240) n
= 10240;
52 n
*= 170; // avg tested
55 // if (mem.maxfreeram < (n + (64 * 1024))) n = mem.maxfreeram - (64 * 1024);
58 if (si
.freeram
< (n
+ (64 * 1024))) n
= si
.freeram
- (64 * 1024);
60 // cprintf("free: %dK, buffer: %dK\n", si.freeram / 1024, n / 1024);
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
86 if (argc
!= 1) return;
88 #if defined(TCONFIG_IPV6) && defined(LINUX26)
89 char src
[INET6_ADDRSTRLEN
];
90 char dst
[INET6_ADDRSTRLEN
];
96 lan6_prefix_len
= nvram_get_int("ipv6_prefix_length");
98 inet_pton(AF_INET6
, nvram_safe_get("ipv6_prefix"), &lan6
);
99 ipv6_router_address(&rip6
);
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
) {
110 if ((f
= fopen("/proc/net/ip_conntrack", "r")) != NULL
) {
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"));
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) {
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) {
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;
155 continue; // another proto family?!
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
) {
169 else if (strncmp(t
, "udp", 3) == 0) {
170 if (strstr(s
, "[ASSURED]") != NULL
) {
180 // count connections per mark
181 if ((p
= strstr(s
, " mark=")) != NULL
) {
182 n
= atoi(p
+ 6) & 0xFF;
183 if (n
<= 10) count
[n
]++;
193 for (i
= 0; i
< 12; ++i
) {
194 p
+= sprintf(p
, ",%d", count
[i
]);
196 web_printf("\nconntrack = [%d%s];\n", count
[12], 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
)
218 #if defined(TCONFIG_IPV6) && defined(LINUX26)
220 char src
[INET6_ADDRSTRLEN
];
221 char dst
[INET6_ADDRSTRLEN
];
223 const unsigned int family
= 2;
224 char src
[INET_ADDRSTRLEN
];
225 char dst
[INET_ADDRSTRLEN
];
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"));
246 #if defined(TCONFIG_IPV6) && defined(LINUX26)
247 struct in6_addr rip6
;
248 struct in6_addr lan6
;
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
);
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 = [");
272 #if defined(TCONFIG_IPV6) && defined(LINUX26)
273 if ((f
= fopen("/proc/net/nf_conntrack", "r")) != NULL
) {
275 if ((f
= fopen("/proc/net/ip_conntrack", "r")) != NULL
) {
278 while (fgets(s
, sizeof(s
), f
)) {
280 if ((p
= strstr(s
, " mark=")) == NULL
) continue;
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;
289 if (sscanf(s
, "%*s %u %u", &proto
, &time
) != 2) continue;
290 if ((p
= strstr(s
+ 14, "src=")) == NULL
) continue;
292 if (sscanf(p
, "src=%s dst=%s %n", src
, dst
, &x
) != 2) continue;
295 if ((proto
== 6) || (proto
== 17)) {
296 if (sscanf(p
, "sport=%s dport=%s %*s bytes=%s %n", sport
, dport
, byteso
, &x
) != 3) continue;
298 if ((q
= strstr(p
, "bytes=")) == NULL
) continue;
299 if (sscanf(q
, "bytes=%s", bytesi
) != 1) continue;
310 if ((inet_addr(src
) & mask
) != lan
) {
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
318 if (sscanf(p
, "src=%s dst=%s", dst
, src
) != 2) continue;
321 else if (rip
!= 0 && inet_addr(dst
) == rip
) continue;
323 #if defined(TCONFIG_IPV6) && defined(LINUX26)
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
))
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
)))
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
);
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
);
352 void asp_ctrate(int argc
, char **argv
)
354 unsigned int a_time
, a_proto
;
355 unsigned int a_bytes_o
, a_bytes_i
;
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
];
368 const unsigned int a_fam
= 2;
369 char a_src
[INET_ADDRSTRLEN
];
370 char a_dst
[INET_ADDRSTRLEN
];
373 unsigned int b_time
, b_proto
;
374 unsigned int b_bytes_o
, b_bytes_i
;
398 mask
= inet_addr(nvram_safe_get("lan_netmask"));
399 rip
= inet_addr(nvram_safe_get("lan_ipaddr"));
402 #if defined(TCONFIG_IPV6) && defined(LINUX26)
403 struct in6_addr rip6
;
404 struct in6_addr lan6
;
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
);
415 if (nvram_match("t_hidelr", "0")) rip
= 0; // hide lan -> router?
417 web_puts("\nctrate = [");
420 #if defined(TCONFIG_IPV6) && defined(LINUX26)
421 const char name
[] = "/proc/net/nf_conntrack";
423 const char name
[] = "/proc/net/ip_conntrack";
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;
438 if ((buffer
=(char *)malloc(1024)) == NULL
) {
439 // can't allocate memory? clean-up and exit
447 count
= fread(buffer
, 1, 1024, a
);
448 fwrite(buffer
, 1, count
, b
);
450 // release/deallocate buffer
453 while (fgets(sa
, sizeof(sa
), 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;
470 if (sscanf(sa
, "%*s %u %u", &a_proto
, &a_time
) != 2) continue;
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;
484 if ((inet_addr(a_src
) & mask
) != lan
) dir_reply
= 1;
485 else if (rip
!= 0 && inet_addr(a_dst
) == rip
) continue;
487 #if defined(TCONFIG_IPV6) && defined(LINUX26)
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
))
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
)))
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;
513 if (sscanf(sb
, "%*s %u %u", &b_proto
, &b_time
) != 2) continue;
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;
530 if (feof(b
) || n
>= MAX_SEARCH
) {
531 // Assume this is a new connection
536 // Reset the search so we don't miss anything
537 fseek(b
, b_pos
, SEEK_SET
);
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) {
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
);
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
);
568 static void retrieveRatesFromTc(const char* deviceName
, unsigned long ratesArray
[])
576 sprintf(s
, "tc -s class ls dev %s", deviceName
);
577 if ((f
= popen(s
, "r")) != NULL
) {
579 while (fgets(s
, sizeof(s
), f
)) {
580 if (strncmp(s
, "class htb 1:", 12) == 0) {
583 else if (strncmp(s
, " rate ", 6) == 0) {
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
;
600 void asp_qrate(int argc
, char **argv
)
602 unsigned long rates
[10];
610 memset(rates
, 0, sizeof(rates
));
611 retrieveRatesFromTc(get_wanface(), rates
);
614 web_puts("\nqrates_out = [0,");
615 for (n
= 0; n
< 10; ++n
) {
616 web_printf("%c%lu", comma
, rates
[n
]);
621 memset(rates
, 0, sizeof(rates
));
622 retrieveRatesFromTc("imq0", rates
);
625 web_puts("\nqrates_in = [0,");
626 for (n
= 0; n
< 10; ++n
) {
627 web_printf("%c%lu", comma
, rates
[n
]);
633 static void layer7_list(const char *path
, int *first
)
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;
645 web_printf("%s'%s'", *first
? "" : ",", name
);
652 void asp_layer7(int argc
, char **argv
)
655 web_puts("\nlayer7 = [");
656 layer7_list("/etc/l7-extra", &first
);
657 layer7_list("/etc/l7-protocols", &first
);
661 void wo_expct(char *url
)
663 f_write_string("/proc/net/expire_early", "15", 0, 0);