httpd, web gui: ipv6 support: include ipv6 routing table
[tomato.git] / release / src / router / httpd / misc.c
blobaed1a9269967007efe8bf0d7107c426395628f26
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 <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 #include <sys/types.h>
20 #include <dirent.h>
21 #include <time.h>
22 #include <sys/statfs.h>
23 #include <netdb.h>
24 #include <net/route.h>
26 #include <wlioctl.h>
27 #include <wlutils.h>
29 // to javascript-safe string
30 char *js_string(const char *s)
32 unsigned char c;
33 char *buffer;
34 char *b;
36 if ((buffer = malloc((strlen(s) * 4) + 1)) != NULL) {
37 b = buffer;
38 while ((c = *s++) != 0) {
39 if ((c == '"') || (c == '\'') || (c == '\\') || (!isprint(c))) {
40 b += sprintf(b, "\\x%02x", c);
42 else {
43 *b++ = c;
46 *b = 0;
48 return buffer;
51 // to html-safe string
52 char *html_string(const char *s)
54 unsigned char c;
55 char *buffer;
56 char *b;
58 if ((buffer = malloc((strlen(s) * 6) + 1)) != NULL) {
59 b = buffer;
60 while ((c = *s++) != 0) {
61 if ((c == '&') || (c == '<') || (c == '>') || (c == '"') || (c == '\'') || (!isprint(c))) {
62 b += sprintf(b, "&#%d;", c);
64 else {
65 *b++ = c;
68 *b = 0;
70 return buffer;
73 // removes \r
74 char *unix_string(const char *s)
76 char *buffer;
77 char *b;
78 char c;
80 if ((buffer = malloc(strlen(s) + 1)) != NULL) {
81 b = buffer;
82 while ((c = *s++) != 0)
83 if (c != '\r') *b++ = c;
84 *b = 0;
86 return buffer;
89 // # days, ##:##:##
90 char *reltime(char *buf, time_t t)
92 int days;
93 int m;
95 if (t < 0) t = 0;
96 days = t / 86400;
97 m = t / 60;
98 sprintf(buf, "%d day%s, %02d:%02d:%02d", days, ((days==1) ? "" : "s"), ((m / 60) % 24), (m % 60), (int)(t % 60));
99 return buf;
102 int get_client_info(char *mac, char *ifname)
104 FILE *f;
105 char s[256];
106 #ifdef TCONFIG_IPV6
107 char ip[INET6_ADDRSTRLEN];
108 #else
109 char ip[INET_ADDRSTRLEN];
110 #endif
113 # ip neigh show fe80:0:0::201:02ff:fe03:0405
114 fe80::201:2ff:fe3:405 dev br0 lladdr 00:01:02:03:04:05 REACHABLE
116 if (clientsai.ss_family == AF_INET) {
117 inet_ntop(clientsai.ss_family, &(((struct sockaddr_in*)&clientsai)->sin_addr), ip, sizeof(ip));
118 sprintf(s, "ip neigh show %s", ip);
120 #ifdef TCONFIG_IPV6
121 else if (clientsai.ss_family == AF_INET6) {
122 inet_ntop(clientsai.ss_family, &(((struct sockaddr_in6*)&clientsai)->sin6_addr), ip, sizeof(ip));
123 if (IN6_IS_ADDR_V4MAPPED( &(((struct sockaddr_in6*)&clientsai)->sin6_addr) ))
124 sprintf(s, "ip neigh show %s", ip + 7); // chop off the ::ffff: to get the ipv4 bit
125 else
126 sprintf(s, "ip neigh show %s", ip);
128 #endif
130 if ((f = popen(s, "r")) != NULL) {
131 while (fgets(s, sizeof(s), f)) {
132 if (sscanf(s, "%*s dev %16s lladdr %17s %*s", ifname, mac) == 2) {
133 pclose(f);
134 return 1;
137 pclose(f);
139 return 0;
143 // <% lanip(mode); %>
144 // <mode>
145 // 1 return first 3 octets (192.168.1)
146 // 2 return last octet (1)
147 // else return full (192.168.1.1)
149 void asp_lanip(int argc, char **argv)
151 char *nv, *p;
152 char s[64];
153 char mode;
155 mode = argc ? *argv[0] : 0;
157 if ((nv = nvram_get("lan_ipaddr")) != NULL) {
158 strcpy(s, nv);
159 if ((p = strrchr(s, '.')) != NULL) {
160 *p = 0;
161 web_puts((mode == '1') ? s : (mode == '2') ? (p + 1) : nv);
166 void asp_lipp(int argc, char **argv)
168 char *one = "1";
169 asp_lanip(1, &one);
172 // <% psup(process); %>
173 // returns 1 if process is running
175 void asp_psup(int argc, char **argv)
177 if (argc == 1) web_printf("%d", pidof(argv[0]) > 0);
180 void wo_vpn_status(char *url)
182 #ifdef TCONFIG_OPENVPN
183 char buf[256];
184 char *type;
185 char *str;
186 int num;
187 FILE *fp;
189 type = 0;
190 if ( (str = webcgi_get("server")) )
191 type = "server";
192 else if ( (str = webcgi_get("client")) )
193 type = "client";
195 num = str? atoi(str): 0;
196 if ( type && num > 0 )
198 // Trigger OpenVPN to update the status file
199 snprintf(&buf[0], sizeof(buf), "vpn%s%d", type, num);
200 killall(&buf[0], SIGUSR2);
202 // Give it a chance to update the file
203 sleep(1);
205 // Read the status file and repeat it verbatim to the caller
206 snprintf(&buf[0], sizeof(buf), "/etc/openvpn/%s%d/status", type, num);
207 fp = fopen(&buf[0], "r");
208 if( fp != NULL )
210 while (fgets(&buf[0], sizeof(buf), fp) != NULL)
211 web_puts(&buf[0]);
212 fclose(fp);
215 #endif
219 # cat /proc/meminfo
220 total: used: free: shared: buffers: cached:
221 Mem: 14872576 12877824 1994752 0 1236992 4837376
222 Swap: 0 0 0
223 MemTotal: 14524 kB
224 MemFree: 1948 kB
225 MemShared: 0 kB
226 Buffers: 1208 kB
227 Cached: 4724 kB
228 SwapCached: 0 kB
229 Active: 4364 kB
230 Inactive: 2952 kB
231 HighTotal: 0 kB
232 HighFree: 0 kB
233 LowTotal: 14524 kB
234 LowFree: 1948 kB
235 SwapTotal: 0 kB
236 SwapFree: 0 kB
240 typedef struct {
241 unsigned long total;
242 unsigned long free;
243 unsigned long shared;
244 unsigned long buffers;
245 unsigned long cached;
246 unsigned long swaptotal;
247 unsigned long swapfree;
248 unsigned long maxfreeram;
249 } meminfo_t;
251 static int get_memory(meminfo_t *m)
253 FILE *f;
254 char s[128];
255 int ok = 0;
257 memset(m, 0, sizeof(*m));
258 if ((f = fopen("/proc/meminfo", "r")) != NULL) {
259 while (fgets(s, sizeof(s), f)) {
260 #ifdef LINUX26
261 if (strncmp(s, "MemTotal:", 9) == 0) {
262 m->total = strtoul(s + 12, NULL, 10) * 1024;
263 ++ok;
265 else if (strncmp(s, "MemFree:", 8) == 0) {
266 m->free = strtoul(s + 12, NULL, 10) * 1024;
267 ++ok;
269 else if (strncmp(s, "Buffers:", 8) == 0) {
270 m->buffers = strtoul(s + 12, NULL, 10) * 1024;
271 ++ok;
273 else if (strncmp(s, "Cached:", 7) == 0) {
274 m->cached = strtoul(s + 12, NULL, 10) * 1024;
275 ++ok;
277 #else
278 if (strncmp(s, "Mem:", 4) == 0) {
279 if (sscanf(s + 6, "%ld %*d %ld %ld %ld %ld", &m->total, &m->free, &m->shared, &m->buffers, &m->cached) == 5)
280 ++ok;
282 #endif
283 else if (strncmp(s, "SwapTotal:", 10) == 0) {
284 m->swaptotal = strtoul(s + 12, NULL, 10) * 1024;
285 ++ok;
287 else if (strncmp(s, "SwapFree:", 9) == 0) {
288 m->swapfree = strtoul(s + 11, NULL, 10) * 1024;
289 ++ok;
290 #ifndef LINUX26
291 break;
292 #endif
295 fclose(f);
297 if (ok == 0) {
298 return 0;
300 m->maxfreeram = m->free;
301 if (nvram_match("t_cafree", "1")) m->maxfreeram += (m->cached + m->buffers);
302 return 1;
305 void asp_sysinfo(int argc, char **argv)
307 struct sysinfo si;
308 char s[64];
309 meminfo_t mem;
311 web_puts("\nsysinfo = {\n");
312 sysinfo(&si);
313 get_memory(&mem);
314 web_printf(
315 "\tuptime: %ld,\n"
316 "\tuptime_s: '%s',\n"
317 "\tloads: [%ld, %ld, %ld],\n"
318 "\ttotalram: %ld,\n"
319 "\tfreeram: %ld,\n"
320 "\tshareram: %ld,\n"
321 "\tbufferram: %ld,\n"
322 "\tcached: %ld,\n"
323 "\ttotalswap: %ld,\n"
324 "\tfreeswap: %ld,\n"
325 "\ttotalfreeram: %ld,\n"
326 "\tprocs: %d\n",
327 si.uptime,
328 reltime(s, si.uptime),
329 si.loads[0], si.loads[1], si.loads[2],
330 mem.total, mem.free,
331 mem.shared, mem.buffers, mem.cached,
332 mem.swaptotal, mem.swapfree,
333 mem.maxfreeram,
334 si.procs);
335 web_puts("};\n");
338 void asp_activeroutes(int argc, char **argv)
340 FILE *f;
341 char s[512];
342 char dev[17];
343 unsigned long dest;
344 unsigned long gateway;
345 unsigned long flags;
346 unsigned long mask;
347 unsigned metric;
348 struct in_addr ia;
349 char s_dest[16];
350 char s_gateway[16];
351 char s_mask[16];
352 int n;
354 web_puts("\nactiveroutes = [");
355 n = 0;
356 if ((f = fopen("/proc/net/route", "r")) != NULL) {
357 while (fgets(s, sizeof(s), f)) {
358 if (sscanf(s, "%16s%lx%lx%lx%*s%*s%u%lx", dev, &dest, &gateway, &flags, &metric, &mask) != 6) continue;
359 if ((flags & RTF_UP) == 0) continue;
360 if (dest != 0) {
361 ia.s_addr = dest;
362 strcpy(s_dest, inet_ntoa(ia));
364 else {
365 strcpy(s_dest, "default");
367 if (gateway != 0) {
368 ia.s_addr = gateway;
369 strcpy(s_gateway, inet_ntoa(ia));
371 else {
372 strcpy(s_gateway, "*");
374 ia.s_addr = mask;
375 strcpy(s_mask, inet_ntoa(ia));
376 web_printf("%s['%s','%s','%s','%s',%u]", n ? "," : "", dev, s_dest, s_gateway, s_mask, metric);
377 ++n;
379 fclose(f);
382 #ifdef TCONFIG_IPV6
383 int pxlen;
384 char addr6x[80];
385 struct sockaddr_in6 snaddr6;
386 char addr6[40], nhop6[40];
388 if (nvram_invmatch("ipv6_service", "")) &&
389 (f = fopen("/proc/net/ipv6_route", "r")) != NULL) {
390 while (fgets(s, sizeof(s), f)) {
391 if (sscanf(s, "%32s%x%*s%*s%32s%x%*s%*s%lx%s\n",
392 addr6x+14, &pxlen, addr6x+40+7, &metric, &flags, dev) != 6) continue;
394 if ((flags & RTF_UP) == 0) continue;
396 int i = 0;
397 char *p = addr6x+14;
398 do {
399 if (!*p) {
400 if (i == 40) { // nul terminator for 1st address?
401 addr6x[39] = 0; // Fixup... need 0 instead of ':'.
402 ++p; // Skip and continue.
403 continue;
405 goto OUT;
407 addr6x[i++] = *p++;
408 if (!((i+1) % 5)) {
409 addr6x[i++] = ':';
411 } while (i < 40+28+7);
413 inet_pton(AF_INET6, addr6x, (struct sockaddr *) &snaddr6.sin6_addr);
414 inet_ntop(AF_INET6, &snaddr6.sin6_addr, addr6, sizeof(addr6));
415 inet_pton(AF_INET6, addr6x + 40, (struct sockaddr *) &snaddr6.sin6_addr);
416 inet_ntop(AF_INET6, &snaddr6.sin6_addr, nhop6, sizeof(nhop6));
418 web_printf("%s['%s','%s/%d','%s','',%u]", n ? "," : "", dev, addr6, pxlen, nhop6, metric);
419 ++n;
421 OUT:
422 fclose(f);
424 #endif
426 web_puts("];\n");
429 void asp_cgi_get(int argc, char **argv)
431 const char *v;
432 int i;
434 for (i = 0; i < argc; ++i) {
435 v = webcgi_get(argv[i]);
436 if (v) web_puts(v);
440 void asp_time(int argc, char **argv)
442 time_t t;
443 char s[64];
445 t = time(NULL);
446 if (t < Y2K) {
447 web_puts("Not Available");
449 else {
450 strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
451 web_puts(s);
455 void asp_wanup(int argc, char **argv)
457 web_puts(check_wanup() ? "1" : "0");
460 void asp_wanstatus(int argc, char **argv)
462 const char *p;
464 if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) {
465 p = "Renewing...";
467 else if (check_wanup()) {
468 p = "Connected";
470 else if (f_exists("/var/lib/misc/wan.connecting")) {
471 p = "Connecting...";
473 else {
474 p = "Disconnected";
476 web_puts(p);
479 void asp_link_uptime(int argc, char **argv)
481 struct sysinfo si;
482 char buf[64];
483 long uptime;
485 buf[0] = '-';
486 buf[1] = 0;
487 if (check_wanup()) {
488 sysinfo(&si);
489 if (f_read("/var/lib/misc/wantime", &uptime, sizeof(uptime)) == sizeof(uptime)) {
490 reltime(buf, si.uptime - uptime);
493 web_puts(buf);
496 void asp_rrule(int argc, char **argv)
498 char s[32];
499 int i;
501 i = nvram_get_int("rruleN");
502 sprintf(s, "rrule%d", i);
503 web_puts("\nrrule = '");
504 web_putj(nvram_safe_get(s));
505 web_printf("';\nrruleN = %d;\n", i);
508 void asp_compmac(int argc, char **argv)
510 char mac[32];
511 char ifname[32];
513 if (get_client_info(mac, ifname)) {
514 web_puts(mac);
518 void asp_ident(int argc, char **argv)
520 web_puth(nvram_safe_get("router_name"));
523 void asp_statfs(int argc, char **argv)
525 struct statfs sf;
526 int mnt;
528 if (argc != 2) return;
530 // used for /cifs/, /jffs/... if it returns squashfs type, assume it's not mounted
531 if ((statfs(argv[0], &sf) != 0) || (sf.f_type == 0x73717368)) {
532 mnt = 0;
533 memset(&sf, 0, sizeof(sf));
534 #ifdef TCONFIG_JFFS2
535 // for jffs, try to get total size from mtd partition
536 if (strncmp(argv[1], "jffs", 4) == 0) {
537 int part;
539 if (mtd_getinfo(argv[1], &part, (int *)&sf.f_blocks)) {
540 sf.f_bsize = 1;
543 #endif
545 else {
546 mnt = 1;
549 web_printf(
550 "\n%s = {\n"
551 "\tmnt: %d,\n"
552 "\tsize: %llu,\n"
553 "\tfree: %llu\n"
554 "};\n",
555 argv[1], mnt,
556 ((uint64_t)sf.f_bsize * sf.f_blocks),
557 ((uint64_t)sf.f_bsize * sf.f_bfree));
560 void asp_notice(int argc, char **argv)
562 char s[256];
563 char buf[2048];
565 if (argc != 1) return;
566 snprintf(s, sizeof(s), "/var/notice/%s", argv[0]);
567 if (f_read_string(s, buf, sizeof(buf)) <= 0) return;
568 web_putj(buf);
571 void wo_wakeup(char *url)
573 char *mac;
574 char *p;
575 char *end;
577 if ((mac = webcgi_get("mac")) != NULL) {
578 end = mac + strlen(mac);
579 while (mac < end) {
580 while ((*mac == ' ') || (*mac == '\t') || (*mac == '\r') || (*mac == '\n')) ++mac;
581 if (*mac == 0) break;
583 p = mac;
584 while ((*p != 0) && (*p != ' ') && (*p != '\r') && (*p != '\n')) ++p;
585 *p = 0;
587 eval("ether-wake", "-b", "-i", nvram_safe_get("lan_ifname"), mac);
588 mac = p + 1;
591 common_redirect();
594 void asp_dns(int argc, char **argv)
596 char s[128];
597 int i;
598 const dns_list_t *dns;
600 dns = get_dns(); // static buffer
601 strcpy(s, "\ndns = [");
602 for (i = 0 ; i < dns->count; ++i) {
603 sprintf(s + strlen(s), "%s'%s:%u'", i ? "," : "", inet_ntoa(dns->dns[i].addr), dns->dns[i].port);
605 strcat(s, "];\n");
606 web_puts(s);
609 void wo_resolve(char *url)
611 char *p;
612 char *ip;
614 char host[NI_MAXHOST];
615 struct addrinfo hints;
616 struct addrinfo *res;
618 memset(&hints, 0, sizeof hints);
619 hints.ai_family = AF_UNSPEC;
620 hints.ai_socktype = SOCK_STREAM;
622 char comma;
623 char *js;
625 comma = ' ';
626 web_puts("\nresolve_data = [\n");
627 if ((p = webcgi_get("ip")) != NULL) {
628 while ((ip = strsep(&p, ",")) != NULL) {
629 if (getaddrinfo(ip, NULL, &hints, &res) != 0) {
630 //error
631 continue;
633 if (getnameinfo(res->ai_addr, res->ai_addrlen, host, sizeof(host), NULL, 0, 0) != 0) continue;
634 js = js_string(host);
635 web_printf("%c['%s','%s']", comma, ip, js);
636 free(js);
637 freeaddrinfo(res);
638 comma = ',';
641 web_puts("];\n");