4 Copyright (C) 2006-2009 Jonathan Zarate
11 #include <sys/sysinfo.h>
13 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <sys/types.h>
22 #include <sys/statfs.h>
24 #include <net/route.h>
33 // to javascript-safe string
34 char *js_string(const char *s
)
40 if ((buffer
= malloc((strlen(s
) * 4) + 1)) != NULL
) {
42 while ((c
= *s
++) != 0) {
43 if ((c
== '"') || (c
== '\'') || (c
== '\\') || (!isprint(c
))) {
44 b
+= sprintf(b
, "\\x%02x", c
);
55 // to html-safe string
56 char *html_string(const char *s
)
62 if ((buffer
= malloc((strlen(s
) * 6) + 1)) != NULL
) {
64 while ((c
= *s
++) != 0) {
65 if ((c
== '&') || (c
== '<') || (c
== '>') || (c
== '"') || (c
== '\'') || (!isprint(c
))) {
66 b
+= sprintf(b
, "&#%d;", c
);
78 char *unix_string(const char *s
)
84 if ((buffer
= malloc(strlen(s
) + 1)) != NULL
) {
86 while ((c
= *s
++) != 0)
87 if (c
!= '\r') *b
++ = c
;
94 char *reltime(char *buf
, time_t t
)
102 sprintf(buf
, "%d day%s, %02d:%02d:%02d", days
, ((days
==1) ? "" : "s"), ((m
/ 60) % 24), (m
% 60), (int)(t
% 60));
106 int get_client_info(char *mac
, char *ifname
)
111 char ip
[INET6_ADDRSTRLEN
];
113 char ip
[INET_ADDRSTRLEN
];
117 # ip neigh show fe80:0:0::201:02ff:fe03:0405
118 fe80::201:2ff:fe3:405 dev br0 lladdr 00:01:02:03:04:05 REACHABLE
120 if (clientsai
.ss_family
== AF_INET
) {
121 inet_ntop(clientsai
.ss_family
, &(((struct sockaddr_in
*)&clientsai
)->sin_addr
), ip
, sizeof(ip
));
122 sprintf(s
, "ip neigh show %s", ip
);
125 else if (clientsai
.ss_family
== AF_INET6
) {
126 inet_ntop(clientsai
.ss_family
, &(((struct sockaddr_in6
*)&clientsai
)->sin6_addr
), ip
, sizeof(ip
));
127 if (IN6_IS_ADDR_V4MAPPED( &(((struct sockaddr_in6
*)&clientsai
)->sin6_addr
) ))
128 sprintf(s
, "ip neigh show %s", ip
+ 7); // chop off the ::ffff: to get the ipv4 bit
130 sprintf(s
, "ip neigh show %s", ip
);
134 if ((f
= popen(s
, "r")) != NULL
) {
135 while (fgets(s
, sizeof(s
), f
)) {
136 if (sscanf(s
, "%*s dev %16s lladdr %17s %*s", ifname
, mac
) == 2) {
147 // <% lanip(mode); %>
149 // 1 return first 3 octets (192.168.1)
150 // 2 return last octet (1)
151 // else return full (192.168.1.1)
153 void asp_lanip(int argc
, char **argv
)
159 mode
= argc
? *argv
[0] : 0;
161 if ((nv
= nvram_get("lan_ipaddr")) != NULL
) {
163 if ((p
= strrchr(s
, '.')) != NULL
) {
165 web_puts((mode
== '1') ? s
: (mode
== '2') ? (p
+ 1) : nv
);
170 void asp_lipp(int argc
, char **argv
)
176 // <% psup(process); %>
177 // returns 1 if process is running
179 void asp_psup(int argc
, char **argv
)
181 if (argc
== 1) web_printf("%d", pidof(argv
[0]) > 0);
184 void wo_vpn_status(char *url
)
186 #ifdef TCONFIG_OPENVPN
194 if ( (str
= webcgi_get("server")) )
196 else if ( (str
= webcgi_get("client")) )
199 num
= str
? atoi(str
): 0;
200 if ( type
&& num
> 0 )
202 // Trigger OpenVPN to update the status file
203 snprintf(&buf
[0], sizeof(buf
), "vpn%s%d", type
, num
);
204 killall(&buf
[0], SIGUSR2
);
206 // Give it a chance to update the file
209 // Read the status file and repeat it verbatim to the caller
210 snprintf(&buf
[0], sizeof(buf
), "/etc/openvpn/%s%d/status", type
, num
);
211 fp
= fopen(&buf
[0], "r");
214 while (fgets(&buf
[0], sizeof(buf
), fp
) != NULL
)
224 total: used: free: shared: buffers: cached:
225 Mem: 14872576 12877824 1994752 0 1236992 4837376
247 unsigned long shared
;
248 unsigned long buffers
;
249 unsigned long cached
;
250 unsigned long swaptotal
;
251 unsigned long swapfree
;
252 unsigned long maxfreeram
;
255 static int get_memory(meminfo_t
*m
)
261 memset(m
, 0, sizeof(*m
));
262 if ((f
= fopen("/proc/meminfo", "r")) != NULL
) {
263 while (fgets(s
, sizeof(s
), f
)) {
265 if (strncmp(s
, "MemTotal:", 9) == 0) {
266 m
->total
= strtoul(s
+ 12, NULL
, 10) * 1024;
269 else if (strncmp(s
, "MemFree:", 8) == 0) {
270 m
->free
= strtoul(s
+ 12, NULL
, 10) * 1024;
273 else if (strncmp(s
, "Buffers:", 8) == 0) {
274 m
->buffers
= strtoul(s
+ 12, NULL
, 10) * 1024;
277 else if (strncmp(s
, "Cached:", 7) == 0) {
278 m
->cached
= strtoul(s
+ 12, NULL
, 10) * 1024;
282 if (strncmp(s
, "Mem:", 4) == 0) {
283 if (sscanf(s
+ 6, "%ld %*d %ld %ld %ld %ld", &m
->total
, &m
->free
, &m
->shared
, &m
->buffers
, &m
->cached
) == 5)
287 else if (strncmp(s
, "SwapTotal:", 10) == 0) {
288 m
->swaptotal
= strtoul(s
+ 12, NULL
, 10) * 1024;
291 else if (strncmp(s
, "SwapFree:", 9) == 0) {
292 m
->swapfree
= strtoul(s
+ 11, NULL
, 10) * 1024;
304 m
->maxfreeram
= m
->free
;
305 if (nvram_match("t_cafree", "1")) m
->maxfreeram
+= (m
->cached
+ m
->buffers
);
310 #define IP6ADDR_MAX_CNT 3 // wan, lan, lan-ll
311 static void print_ipv6_addrs(void)
313 char buf
[INET6_ADDRSTRLEN
];
316 struct ifaddrs
*ifap
, *ifa
;
317 struct sockaddr_in6
*s6
;
319 if (!ipv6_enabled() || (getifaddrs(&ifap
) != 0))
323 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
324 if ((ifa
->ifa_addr
== NULL
) || (ifa
->ifa_addr
->sa_family
!= AF_INET6
))
327 s6
= (struct sockaddr_in6
*)(ifa
->ifa_addr
);
329 if (strncmp(ifa
->ifa_name
, nvram_safe_get("lan_ifname"), IFNAMSIZ
) == 0) {
330 if (IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
))
335 else if (strncmp(ifa
->ifa_name
, get_wan6face(), IFNAMSIZ
) == 0) {
336 if (!IN6_IS_ADDR_LINKLOCAL(&s6
->sin6_addr
))
344 if (inet_ntop(ifa
->ifa_addr
->sa_family
, &(s6
->sin6_addr
), buf
, sizeof(buf
)) != NULL
) {
345 web_printf("\tip6_%s: '%s',\n",
347 if (++found
>= IP6ADDR_MAX_CNT
)
355 void asp_calc6rdlocalprefix(int argc
, char **argv
)
357 struct in6_addr prefix_addr
, local_prefix_addr
;
358 int prefix_len
= 0, relay_prefix_len
= 0, local_prefix_len
= 0;
359 struct in_addr wanip_addr
;
360 char local_prefix
[INET6_ADDRSTRLEN
];
363 if (argc
!= 3) return;
365 inet_pton(AF_INET6
, argv
[0], &prefix_addr
);
366 prefix_len
= atoi(argv
[1]);
367 relay_prefix_len
= atoi(argv
[2]);
368 inet_pton(AF_INET
, get_wanip(), &wanip_addr
);
370 if (calc_6rd_local_prefix(&prefix_addr
, prefix_len
, relay_prefix_len
,
371 &wanip_addr
, &local_prefix_addr
, &local_prefix_len
) &&
372 inet_ntop(AF_INET6
, &local_prefix_addr
, local_prefix
, sizeof(local_prefix
)) != NULL
) {
373 sprintf(s
, "\nlocal_prefix = '%s/%d';\n", local_prefix
, local_prefix_len
);
383 dev: size erasesize name
384 mtd0: 00020000 00010000 "pmon"
385 mtd1: 007d0000 00010000 "linux"
393 if ((f
= fopen("/proc/mtd", "r")) != NULL
) {
394 while (fgets(s
, sizeof(s
), f
)) {
395 if (sscanf(s
, "%*s %X %*s %16s", &size
, partname
) != 2) continue;
396 if (strcmp(partname
, "\"linux\"") == 0) {
404 if (nvram_match("boardtype", "0x052b") && nvram_match("boardrev", "02")) return 128; //Netgear 3500L v2 has 128MB NAND flash but linux partition has only 32MB
405 else if ((size
> 0x2000000) && (size
< 0x4000000)) return 64;
406 else if ((size
> 0x1000000) && (size
< 0x2000000)) return 32;
407 else if ((size
> 0x800000) && (size
< 0x1000000)) return 16;
408 else if ((size
> 0x400000) && (size
< 0x800000)) return 8;
409 else if ((size
> 0x200000) && (size
< 0x400000)) return 4;
410 else if ((size
> 0x100000) && (size
< 0x200000)) return 2;
418 void asp_etherstates(int argc
, char **argv
)
421 char s
[32], *a
, b
[16];
424 if (nvram_match("lan_state", "1")) {
426 web_puts("\netherstates = {");
428 system("/usr/sbin/ethstate");
430 if ((f
= fopen("/tmp/ethernet.state", "r")) != NULL
) {
431 while (fgets(s
, sizeof(s
), f
)) {
432 if (sscanf(s
, "Port 0: %s", b
) == 1) a
="port0";
433 else if (sscanf(s
, "Port 1: %s", b
) == 1) a
="port1";
434 else if (sscanf(s
, "Port 2: %s", b
) == 1) a
="port2";
435 else if (sscanf(s
, "Port 3: %s", b
) == 1) a
="port3";
436 else if (sscanf(s
, "Port 4: %s", b
) == 1) a
="port4";
439 web_printf("%s\t%s: '%s'", n
? ",\n" : "", a
, b
);
446 web_puts("\netherstates = {\tport0: 'disabled'\n};\n");
450 void asp_anonupdate(int argc
, char **argv
)
453 char s
[32], *a
, b
[16];
456 if ( nvram_match("tomatoanon_answer", "1") && nvram_match("tomatoanon_enable", "1") ) {
458 web_puts("\nanonupdate = {");
461 if ((f
= fopen("/tmp/anon.result", "r")) != NULL
) {
462 while (fgets(s
, sizeof(s
), f
)) {
463 if (sscanf(s
, "have_update=%s", b
) == 1) a
="update";
466 web_printf("%s\t%s: '%s'", n
? ",\n" : "", a
, b
);
473 web_puts("\nanonupdate = {\tupdate: 'no'\n};\n");
477 void asp_sysinfo(int argc
, char **argv
)
483 char system_type
[64];
488 get_cpuinfo(system_type
, cpu_model
, bogomips
, cpuclk
);
490 web_puts("\nsysinfo = {\n");
499 "\tuptime_s: '%s',\n"
500 "\tloads: [%ld, %ld, %ld],\n"
504 "\tbufferram: %ld,\n"
506 "\ttotalswap: %ld,\n"
508 "\ttotalfreeram: %ld,\n"
511 "\tsystemtype: '%s',\n"
512 "\tcpumodel: '%s',\n"
513 "\tbogomips: '%s',\n"
516 reltime(s
, si
.uptime
),
517 si
.loads
[0], si
.loads
[1], si
.loads
[2],
519 mem
.shared
, mem
.buffers
, mem
.cached
,
520 mem
.swaptotal
, mem
.swapfree
,
532 void asp_activeroutes(int argc
, char **argv
)
538 unsigned long gateway
;
548 web_puts("\nactiveroutes = [");
550 if ((f
= fopen("/proc/net/route", "r")) != NULL
) {
551 while (fgets(s
, sizeof(s
), f
)) {
552 if (sscanf(s
, "%16s%lx%lx%lx%*s%*s%u%lx", dev
, &dest
, &gateway
, &flags
, &metric
, &mask
) != 6) continue;
553 if ((flags
& RTF_UP
) == 0) continue;
556 strcpy(s_dest
, inet_ntoa(ia
));
559 strcpy(s_dest
, "default");
563 strcpy(s_gateway
, inet_ntoa(ia
));
566 strcpy(s_gateway
, "*");
569 strcpy(s_mask
, inet_ntoa(ia
));
570 web_printf("%s['%s','%s','%s','%s',%u]", n
? "," : "", dev
, s_dest
, s_gateway
, s_mask
, metric
);
579 struct sockaddr_in6 snaddr6
;
580 char addr6
[40], nhop6
[40];
582 if ((ipv6_enabled()) &&
583 (f
= fopen("/proc/net/ipv6_route", "r")) != NULL
) {
584 while (fgets(s
, sizeof(s
), f
)) {
585 if (sscanf(s
, "%32s%x%*s%*s%32s%x%*s%*s%lx%s\n",
586 addr6x
+14, &pxlen
, addr6x
+40+7, &metric
, &flags
, dev
) != 6) continue;
588 if ((flags
& RTF_UP
) == 0) continue;
594 if (i
== 40) { // nul terminator for 1st address?
595 addr6x
[39] = 0; // Fixup... need 0 instead of ':'.
596 ++p
; // Skip and continue.
605 } while (i
< 40+28+7);
607 inet_pton(AF_INET6
, addr6x
, (struct sockaddr
*) &snaddr6
.sin6_addr
);
608 if (IN6_IS_ADDR_UNSPECIFIED(&snaddr6
.sin6_addr
))
609 strcpy(addr6
, "default");
611 inet_ntop(AF_INET6
, &snaddr6
.sin6_addr
, addr6
, sizeof(addr6
));
613 inet_pton(AF_INET6
, addr6x
+ 40, (struct sockaddr
*) &snaddr6
.sin6_addr
);
614 if (IN6_IS_ADDR_UNSPECIFIED(&snaddr6
.sin6_addr
))
617 inet_ntop(AF_INET6
, &snaddr6
.sin6_addr
, nhop6
, sizeof(nhop6
));
619 web_printf("%s['%s','%s','%s','%d',%u]", n
? "," : "", dev
, addr6
, nhop6
, pxlen
, metric
);
630 void asp_cgi_get(int argc
, char **argv
)
635 for (i
= 0; i
< argc
; ++i
) {
636 v
= webcgi_get(argv
[i
]);
641 void asp_time(int argc
, char **argv
)
648 web_puts("Not Available");
651 strftime(s
, sizeof(s
), "%a, %d %b %Y %H:%M:%S %z", localtime(&t
));
657 void asp_mmcid(int argc
, char **argv
) {
659 char s
[32], *a
, b
[16];
662 web_puts("\nmmcid = {");
664 if ((f
= fopen("/proc/mmc/status", "r")) != NULL
) {
665 while (fgets(s
, sizeof(s
), f
)) {
667 if (sscanf(s
, "Card Type : %16s", b
) == 1) a
="type";
668 else if (sscanf(s
, "Spec Version : %16s", b
) == 1) a
="spec";
669 else if (sscanf(s
, "Num. of Blocks : %d", &size
) == 1) { a
="size"; snprintf(b
,sizeof(b
),"%lld",((unsigned long long)size
)*512); }
670 else if (sscanf(s
, "Voltage Range : %16s", b
) == 1) a
="volt";
671 else if (sscanf(s
, "Manufacture ID : %16s", b
) == 1) a
="manuf";
672 else if (sscanf(s
, "Application ID : %16s", b
) == 1) a
="appl";
673 else if (sscanf(s
, "Product Name : %16s", b
) == 1) a
="prod";
674 else if (sscanf(s
, "Revision : %16s", b
) == 1) a
="rev";
675 else if (sscanf(s
, "Serial Number : %16s", b
) == 1) a
="serial";
676 else if (sscanf(s
, "Manu. Date : %8c", b
) == 1) { a
="date"; b
[9]=0; }
678 web_printf(size
==1 ? "%s\t%s: '%s'" : "%s\t%s: %s", n
? ",\n" : "", a
, b
);
687 void asp_wanup(int argc
, char **argv
)
689 web_puts(check_wanup() ? "1" : "0");
692 void asp_wanstatus(int argc
, char **argv
)
696 if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) {
699 else if (check_wanup()) {
702 else if (f_exists("/var/lib/misc/wan.connecting")) {
711 void asp_link_uptime(int argc
, char **argv
)
721 if (f_read("/var/lib/misc/wantime", &uptime
, sizeof(uptime
)) == sizeof(uptime
)) {
722 reltime(buf
, si
.uptime
- uptime
);
728 void asp_rrule(int argc
, char **argv
)
733 i
= nvram_get_int("rruleN");
734 sprintf(s
, "rrule%d", i
);
735 web_puts("\nrrule = '");
736 web_putj(nvram_safe_get(s
));
737 web_printf("';\nrruleN = %d;\n", i
);
740 void asp_compmac(int argc
, char **argv
)
745 if (get_client_info(mac
, ifname
)) {
750 void asp_ident(int argc
, char **argv
)
752 web_puth(nvram_safe_get("router_name"));
755 void asp_statfs(int argc
, char **argv
)
760 if (argc
!= 2) return;
762 // used for /cifs/, /jffs/... if it returns squashfs type, assume it's not mounted
763 if ((statfs(argv
[0], &sf
) != 0) || (sf
.f_type
== 0x73717368)) {
765 memset(&sf
, 0, sizeof(sf
));
767 // for jffs, try to get total size from mtd partition
768 if (strncmp(argv
[1], "jffs", 4) == 0) {
771 if (mtd_getinfo(argv
[1], &part
, (int *)&sf
.f_blocks
)) {
788 ((uint64_t)sf
.f_bsize
* sf
.f_blocks
),
789 ((uint64_t)sf
.f_bsize
* sf
.f_bfree
));
792 void asp_notice(int argc
, char **argv
)
797 if (argc
!= 1) return;
798 snprintf(s
, sizeof(s
), "/var/notice/%s", argv
[0]);
799 if (f_read_string(s
, buf
, sizeof(buf
)) <= 0) return;
803 void wo_wakeup(char *url
)
809 if ((mac
= webcgi_get("mac")) != NULL
) {
810 end
= mac
+ strlen(mac
);
812 while ((*mac
== ' ') || (*mac
== '\t') || (*mac
== '\r') || (*mac
== '\n')) ++mac
;
813 if (*mac
== 0) break;
816 while ((*p
!= 0) && (*p
!= ' ') && (*p
!= '\r') && (*p
!= '\n')) ++p
;
819 eval("ether-wake", "-b", "-i", nvram_safe_get("lan_ifname"), mac
);
820 if (strcmp(nvram_safe_get("lan1_ifname"), "") != 0)
821 eval("ether-wake", "-b", "-i", nvram_safe_get("lan1_ifname"), mac
);
822 if (strcmp(nvram_safe_get("lan2_ifname"), "") != 0)
823 eval("ether-wake", "-b", "-i", nvram_safe_get("lan2_ifname"), mac
);
824 if (strcmp(nvram_safe_get("lan3_ifname"), "") != 0)
825 eval("ether-wake", "-b", "-i", nvram_safe_get("lan3_ifname"), mac
);
832 void asp_dns(int argc
, char **argv
)
836 const dns_list_t
*dns
;
838 dns
= get_dns(); // static buffer
839 strcpy(s
, "\ndns = [");
840 for (i
= 0 ; i
< dns
->count
; ++i
) {
841 sprintf(s
+ strlen(s
), "%s'%s:%u'", i
? "," : "", inet_ntoa(dns
->dns
[i
].addr
), dns
->dns
[i
].port
);
847 int resolve_addr(const char *ip
, char *host
)
849 struct addrinfo hints
;
850 struct addrinfo
*res
;
853 memset(&hints
, 0, sizeof(hints
));
854 hints
.ai_family
= AF_UNSPEC
;
855 hints
.ai_socktype
= SOCK_STREAM
;
857 ret
= getaddrinfo(ip
, NULL
, &hints
, &res
);
859 ret
= getnameinfo(res
->ai_addr
, res
->ai_addrlen
, host
, NI_MAXHOST
, NULL
, 0, 0);
865 void wo_resolve(char *url
)
869 char host
[NI_MAXHOST
];
874 web_puts("\nresolve_data = [\n");
875 if ((p
= webcgi_get("ip")) != NULL
) {
876 while ((ip
= strsep(&p
, ",")) != NULL
) {
877 if (resolve_addr(ip
, host
) != 0) continue;
878 js
= js_string(host
);
879 web_printf("%c['%s','%s']", comma
, ip
, js
);