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 static void ctvbuf(FILE *f
)
35 if ((p
= nvram_get("ct_max")) != NULL
) {
38 else if (n
< 1024) n
= 1024;
39 else if (n
> 10240) n
= 10240;
47 if (f_read_string("/proc/sys/net/ipv4/ip_conntrack_max", s
, sizeof(s
)) > 0) n
= atoi(s
);
49 if (n
< 1024) n
= 1024;
50 else if (n
> 10240) n
= 10240;
53 n
*= 170; // avg tested
56 // if (mem.maxfreeram < (n + (64 * 1024))) n = mem.maxfreeram - (64 * 1024);
59 if (si
.freeram
< (n
+ (64 * 1024))) n
= si
.freeram
- (64 * 1024);
61 // cprintf("free: %dK, buffer: %dK\n", si.freeram / 1024, n / 1024);
65 setvbuf(f
, NULL
, _IOFBF
, n
);
66 // cprintf("setvbuf = %d\n", n);
70 void asp_ctcount(int argc
, char **argv
)
72 static const char *states
[10] = {
73 "NONE", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT",
74 "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN" };
75 int count
[13]; // tcp(10) + udp(2) + total(1) = 13 / max classes = 10
87 if (argc
!= 1) return;
89 #if defined(TCONFIG_IPV6) && defined(LINUX26)
90 char src
[INET6_ADDRSTRLEN
];
91 char dst
[INET6_ADDRSTRLEN
];
97 lan6_prefix_len
= nvram_get_int("ipv6_prefix_length");
99 inet_pton(AF_INET6
, nvram_safe_get("ipv6_prefix"), &lan6
);
100 ipv6_router_address(&rip6
);
104 mode
= atoi(argv
[0]);
106 memset(count
, 0, sizeof(count
));
108 #if defined(TCONFIG_IPV6) && defined(LINUX26)
109 if ((f
= fopen("/proc/net/nf_conntrack", "r")) != NULL
) {
111 if ((f
= fopen("/proc/net/ip_conntrack", "r")) != NULL
) {
113 ctvbuf(f
); // if possible, read in one go
115 if (nvram_match("t_hidelr", "1")) {
116 mask
= inet_addr(nvram_safe_get("lan_netmask"));
117 rip
= inet_addr(nvram_safe_get("lan_ipaddr"));
121 rip
= lan
= mask
= 0;
124 while (fgets(s
, sizeof(s
), f
)) {
125 #if defined(TCONFIG_IPV6) && defined(LINUX26)
126 if (strncmp(s
, "ipv4", 4) == 0) {
133 // src=x.x.x.x dst=x.x.x.x // DIR_ORIGINAL
134 if ((p
= strstr(t
+ 14, "src=")) == NULL
) continue;
135 if ((inet_addr(p
+ 4) & mask
) == lan
) {
136 if ((p
= strstr(p
+ 13, "dst=")) == NULL
) continue;
137 if (inet_addr(p
+ 4) == rip
) continue;
140 #if defined(TCONFIG_IPV6) && defined(LINUX26)
142 else if (strncmp(s
, "ipv6", 4) == 0) {
146 if ((p
= strstr(t
+ 14, "src=")) == NULL
) continue;
147 if (sscanf(p
, "src=%s dst=%s", src
, dst
) != 2) continue;
149 if (inet_pton(AF_INET6
, src
, &in6
) <= 0) continue;
150 inet_ntop(AF_INET6
, &in6
, src
, sizeof(src
));
152 if (!IP6_PREFIX_NOT_MATCH(lan6
, in6
, lan6_prefix_len
)) continue;
156 continue; // another proto family?!
161 // count connections per state
162 if (strncmp(t
, "tcp", 3) == 0) {
163 for (i
= 9; i
>= 0; --i
) {
164 if (strstr(s
, states
[i
]) != NULL
) {
170 else if (strncmp(t
, "udp", 3) == 0) {
171 if (strstr(s
, "[ASSURED]") != NULL
) {
181 // count connections per mark
182 if ((p
= strstr(s
, " mark=")) != NULL
) {
183 n
= atoi(p
+ 6) & 0xFF;
184 if (n
<= 10) count
[n
]++;
194 for (i
= 0; i
< 12; ++i
) {
195 p
+= sprintf(p
, ",%d", count
[i
]);
197 web_printf("\nconntrack = [%d%s];\n", count
[12], s
);
201 for (i
= 1; i
< 11; ++i
) {
202 p
+= sprintf(p
, ",%d", count
[i
]);
204 web_printf("\nnfmarks = [%d%s];\n", count
[0], s
);
208 void asp_ctdump(int argc
, char **argv
)
219 #if defined(TCONFIG_IPV6) && defined(LINUX26)
221 char src
[INET6_ADDRSTRLEN
];
222 char dst
[INET6_ADDRSTRLEN
];
224 const unsigned int family
= 2;
225 char src
[INET_ADDRSTRLEN
];
226 char dst
[INET_ADDRSTRLEN
];
239 if (argc
!= 1) return;
241 findmark
= atoi(argv
[0]);
243 mask
= inet_addr(nvram_safe_get("lan_netmask"));
244 rip
= inet_addr(nvram_safe_get("lan_ipaddr"));
247 #if defined(TCONFIG_IPV6) && defined(LINUX26)
248 struct in6_addr rip6
;
249 struct in6_addr lan6
;
253 lan6_prefix_len
= nvram_get_int("ipv6_prefix_length");
254 if (ipv6_enabled()) {
255 inet_pton(AF_INET6
, nvram_safe_get("ipv6_prefix"), &lan6
);
256 ipv6_router_address(&rip6
);
260 if (nvram_match("t_hidelr", "0")) rip
= 0; // hide lan -> router?
264 /proc/net/nf_conntrack prefix (compared to ip_conntrack):
265 "ipvx" + 5 spaces + "2" or "10" + 1 space
267 add bytes out/in to table
271 web_puts("\nctdump = [");
273 #if defined(TCONFIG_IPV6) && defined(LINUX26)
274 if ((f
= fopen("/proc/net/nf_conntrack", "r")) != NULL
) {
276 if ((f
= fopen("/proc/net/ip_conntrack", "r")) != NULL
) {
279 while (fgets(s
, sizeof(s
), f
)) {
281 if ((p
= strstr(s
, " mark=")) == NULL
) continue;
283 rule
= (mark
>> 20) & 0xFF;
284 if ((mark
&= 0xFF) > 10) mark
= 0;
285 if ((findmark
!= -1) && (mark
!= findmark
)) continue;
286 #if defined(TCONFIG_IPV6) && defined(LINUX26)
287 if (sscanf(s
, "%*s %u %*s %u %u", &family
, &proto
, &time
) != 3) continue;
288 if ((p
= strstr(s
+ 25, "src=")) == NULL
) continue;
290 if (sscanf(s
, "%*s %u %u", &proto
, &time
) != 2) continue;
291 if ((p
= strstr(s
+ 14, "src=")) == NULL
) continue;
293 if (sscanf(p
, "src=%s dst=%s %n", src
, dst
, &x
) != 2) continue;
296 if ((proto
== 6) || (proto
== 17)) {
297 if (sscanf(p
, "sport=%s dport=%s %*s bytes=%s %n", sport
, dport
, byteso
, &x
) != 3) continue;
299 if ((q
= strstr(p
, "bytes=")) == NULL
) continue;
300 if (sscanf(q
, "bytes=%s", bytesi
) != 1) continue;
311 if ((inet_addr(src
) & mask
) != lan
) {
314 if ((p
= strstr(p
, "src=")) == NULL
) continue;
315 if ((proto
== 6) || (proto
== 17)) {
316 if (sscanf(p
, "src=%s dst=%s sport=%s dport=%s", dst
, src
, dport
, sport
) != 4) continue; // intentionally backwards
319 if (sscanf(p
, "src=%s dst=%s", dst
, src
) != 2) continue;
322 else if (rip
!= 0 && inet_addr(dst
) == rip
) continue;
324 #if defined(TCONFIG_IPV6) && defined(LINUX26)
326 if (inet_pton(AF_INET6
, src
, &in6
) <= 0) continue;
327 inet_ntop(AF_INET6
, &in6
, src
, sizeof(src
));
329 if (IP6_PREFIX_NOT_MATCH(lan6
, in6
, lan6_prefix_len
))
332 if (inet_pton(AF_INET6
, dst
, &in6
) <= 0) continue;
333 inet_ntop(AF_INET6
, &in6
, dst
, sizeof(dst
));
335 if (dir_reply
== 0 && rip
!= 0 && (IN6_ARE_ADDR_EQUAL(&rip6
, &in6
)))
341 if (dir_reply
== 1) {
342 web_printf("%c[%u,%u,'%s','%s','%s','%s','%s','%s',%d,%d]", comma
, proto
, time
, dst
, src
, dport
, sport
, bytesi
, byteso
, mark
, rule
);
345 web_printf("%c[%u,%u,'%s','%s','%s','%s','%s','%s',%d,%d]", comma
, proto
, time
, src
, dst
, sport
, dport
, byteso
, bytesi
, mark
, rule
);
353 void asp_ctrate(int argc
, char **argv
)
355 unsigned int a_time
, a_proto
;
356 unsigned int a_bytes_o
, a_bytes_i
;
364 #if defined(TCONFIG_IPV6) && defined(LINUX26)
365 unsigned int a_fam
, b_fam
;
366 char a_src
[INET6_ADDRSTRLEN
];
367 char a_dst
[INET6_ADDRSTRLEN
];
369 const unsigned int a_fam
= 2;
370 char a_src
[INET_ADDRSTRLEN
];
371 char a_dst
[INET_ADDRSTRLEN
];
374 unsigned int b_time
, b_proto
;
375 unsigned int b_bytes_o
, b_bytes_i
;
399 mask
= inet_addr(nvram_safe_get("lan_netmask"));
400 rip
= inet_addr(nvram_safe_get("lan_ipaddr"));
403 #if defined(TCONFIG_IPV6) && defined(LINUX26)
404 struct in6_addr rip6
;
405 struct in6_addr lan6
;
409 lan6_prefix_len
= nvram_get_int("ipv6_prefix_length");
410 if (ipv6_enabled()) {
411 inet_pton(AF_INET6
, nvram_safe_get("ipv6_prefix"), &lan6
);
412 ipv6_router_address(&rip6
);
416 if (nvram_match("t_hidelr", "0")) rip
= 0; // hide lan -> router?
418 web_puts("\nctrate = [");
421 #if defined(TCONFIG_IPV6) && defined(LINUX26)
422 const char name
[] = "/proc/net/nf_conntrack";
424 const char name
[] = "/proc/net/ip_conntrack";
427 if (argc
!= 2) return;
429 delay
= atoi(argv
[0]);
430 thres
= atoi(argv
[1]) * delay
;
432 if ((a
= fopen(name
, "r")) == NULL
) return;
433 if ((b
= tmpfile()) == NULL
) return;
439 if ((buffer
=(char *)malloc(1024)) == NULL
) {
440 // can't allocate memory? clean-up and exit
448 count
= fread(buffer
, 1, 1024, a
);
449 fwrite(buffer
, 1, count
, b
);
451 // release/deallocate buffer
454 while (fgets(sa
, sizeof(sa
), a
)) {
462 usleep(1000000 * (int)delay
);
464 #define MAX_SEARCH 10
466 // a = current, b = previous
467 while (fgets(sa
, sizeof(sa
), a
)) {
468 #if defined(TCONFIG_IPV6) && defined(LINUX26)
469 if (sscanf(sa
, "%*s %u %*s %u %u", &a_fam
, &a_proto
, &a_time
) != 3) continue;
471 if (sscanf(sa
, "%*s %u %u", &a_proto
, &a_time
) != 2) continue;
473 if ((a_proto
!= 6) && (a_proto
!= 17)) continue;
474 if ((p
= strstr(sa
, "src=")) == NULL
) continue;
476 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;
478 if ((q
= strstr(p
+x
, "bytes=")) == NULL
) continue;
479 if (sscanf(q
, "bytes=%u", &a_bytes_i
) != 1) continue;
485 if ((inet_addr(a_src
) & mask
) != lan
) dir_reply
= 1;
486 else if (rip
!= 0 && inet_addr(a_dst
) == rip
) continue;
488 #if defined(TCONFIG_IPV6) && defined(LINUX26)
490 if (inet_pton(AF_INET6
, a_src
, &in6
) <= 0) continue;
491 inet_ntop(AF_INET6
, &in6
, a_src
, sizeof(a_src
));
493 if (IP6_PREFIX_NOT_MATCH(lan6
, in6
, lan6_prefix_len
))
496 if (inet_pton(AF_INET6
, a_dst
, &in6
) <= 0) continue;
497 inet_ntop(AF_INET6
, &in6
, a_dst
, sizeof(a_dst
));
499 if (dir_reply
== 0 && rip
!= 0 && (IN6_ARE_ADDR_EQUAL(&rip6
, &in6
)))
509 while (fgets(sb
, sizeof(sb
), b
) && ++n
< MAX_SEARCH
) {
510 #if defined(TCONFIG_IPV6) && defined(LINUX26)
511 if (sscanf(sb
, "%*s %u %*s %u %u", &b_fam
, &b_proto
, &b_time
) != 3) continue;
512 if ((b_fam
!= a_fam
)) continue;
514 if (sscanf(sb
, "%*s %u %u", &b_proto
, &b_time
) != 2) continue;
516 if ((b_proto
!= a_proto
)) continue;
517 if ((q
= strstr(sb
, "src=")) == NULL
) continue;
519 if (strncmp(p
, q
, (size_t)len
)) continue;
521 // Ok, they should be the same now. Grab the byte counts.
522 if ((q
= strstr(q
+len
, "bytes=")) == NULL
) continue;
523 if (sscanf(q
, "bytes=%u", &b_bytes_o
) != 1) continue;
525 if ((q
= strstr(q
+len
, "bytes=")) == NULL
) continue;
526 if (sscanf(q
, "bytes=%u", &b_bytes_i
) != 1) continue;
531 if (feof(b
) || n
>= MAX_SEARCH
) {
532 // Assume this is a new connection
537 // Reset the search so we don't miss anything
538 fseek(b
, b_pos
, SEEK_SET
);
542 outbytes
= ((long)a_bytes_o
- (long)b_bytes_o
);
543 inbytes
= ((long)a_bytes_i
- (long)b_bytes_i
);
545 if ((outbytes
< thres
) && (inbytes
< thres
)) continue;
547 if (dir_reply
== 1 && a_fam
== 2) {
549 if ((q
= strstr(p
+x
, "src=")) == NULL
) continue;
550 if (sscanf(q
, "src=%s dst=%s sport=%s dport=%s", a_dst
, a_src
, a_dport
, a_sport
) != 4) continue;
553 if (dir_reply
== 1) {
554 web_printf("%c[%u,'%s','%s','%s','%s',%li,%li]",
555 comma
, a_proto
, a_dst
, a_src
, a_dport
, a_sport
, inbytes
, outbytes
);
558 web_printf("%c[%u,'%s','%s','%s','%s',%li,%li]",
559 comma
, a_proto
, a_src
, a_dst
, a_sport
, a_dport
, outbytes
, inbytes
);
570 void asp_qrate(int argc
, char **argv
)
574 unsigned long rates
[10];
584 memset(rates
, 0, sizeof(rates
));
585 sprintf(s
, "tc -s class ls dev %s", get_wanface());
586 if ((f
= popen(s
, "r")) != NULL
) {
588 while (fgets(s
, sizeof(s
), f
)) {
589 if (strncmp(s
, "class htb 1:", 12) == 0) {
592 else if (strncmp(s
, " rate ", 6) == 0) {
595 if ((n
>= 1) && (n
<= 10)) {
596 u
= strtoul(s
+ 6, &e
, 10);
597 if (*e
== 'K') u
*= 1000;
598 else if (*e
== 'M') u
*= 1000 * 1000;
609 web_puts("\nqrates = [0,");
610 for (n
= 0; n
< 10; ++n
) {
611 web_printf("%c%lu", comma
, rates
[n
]);
617 static void layer7_list(const char *path
, int *first
)
624 if ((dir
= opendir(path
)) != NULL
) {
625 while ((de
= readdir(dir
)) != NULL
) {
626 strlcpy(name
, de
->d_name
, sizeof(name
));
627 if ((p
= strstr(name
, ".pat")) == NULL
) continue;
629 web_printf("%s'%s'", *first
? "" : ",", name
);
636 void asp_layer7(int argc
, char **argv
)
639 web_puts("\nlayer7 = [");
640 layer7_list("/etc/l7-extra", &first
);
641 layer7_list("/etc/l7-protocols", &first
);
645 void wo_expct(char *url
)
647 f_write_string("/proc/net/expire_early", "15", 0, 0);