4 Copyright (C) 2006-2009 Jonathan Zarate
10 #include <sys/sysinfo.h>
12 #include <arpa/inet.h>
16 // #define DEBUG_NOEXECSERVICE
17 // #define DEBUG_NVRAMSET(k, v) cprintf("nvram set %s=%s\n", k, v);
18 #define DEBUG_NVRAMSET(k, v) do { } while(0);
21 char *post_buf
= NULL
;
25 static void asp_css(int argc
, char **argv
);
26 static void asp_resmsg(int argc
, char **argv
);
29 static void wo_tomato(char *url
);
30 static void wo_update(char *url
);
31 static void wo_service(char *url
);
32 static void wo_shutdown(char *url
);
33 static void wo_nvcommit(char *url
);
34 // static void wo_logout(char *url);
37 // ----------------------------------------------------------------------------
40 void exec_service(const char *action
)
44 _dprintf("exec_service: %s\n", action
);
47 while ((!nvram_match("action_service", "")) && (i
-- > 0)) {
48 _dprintf("%s: waiting before %d\n", __FUNCTION__
, i
);
52 nvram_set("action_service", action
);
56 while ((nvram_match("action_service", (char *)action
)) && (i
-- > 0)) {
57 _dprintf("%s: waiting after %d\n", __FUNCTION__
, i
);
62 if (atoi(webcgi_safeget("_service_wait", ""))) {
64 while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) {
65 _dprintf("%s: waiting after %d\n", __FUNCTION__, i);
72 static void wi_generic_noid(char *url
, int len
, char *boundary
)
75 if (len
>= (32 * 1024)) {
76 // syslog(LOG_WARNING, "POST max");
80 if (post_buf
) free(post_buf
);
81 if ((post_buf
= malloc(len
+ 1)) == NULL
) {
82 // syslog(LOG_CRIT, "Unable to allocate post buffer");
86 if (web_read_x(post_buf
, len
) != len
) {
90 webcgi_init(post_buf
);
94 void wi_generic(char *url
, int len
, char *boundary
)
96 wi_generic_noid(url
, len
, boundary
);
100 // !!TB - CGI Support
101 void wi_cgi_bin(char *url
, int len
, char *boundary
)
103 if (post_buf
) free(post_buf
);
107 if (len
>= (32 * 1024)) {
108 syslog(LOG_WARNING
, "POST length exceeded maximum allowed");
113 if ((post_buf
= malloc(len
+ 1)) == NULL
) {
116 if (web_read_x(post_buf
, len
) != len
) {
124 static void _execute_command(char *url
, char *command
, char *query
, char *output
)
126 char webExecFile
[] = "/tmp/.wxXXXXXX";
127 char webQueryFile
[] = "/tmp/.wqXXXXXX";
131 if ((fe
= mkstemp(webExecFile
)) < 0)
134 if ((fq
= mkstemp(webQueryFile
)) < 0) {
141 if ((f
= fdopen(fe
, "wb")) != NULL
) {
144 "export REQUEST_METHOD=\"%s\"\n"
148 post
? "POST" : "GET", getenv("PATH"),
149 command
? "" : "./", command
? command
: url
,
150 query
? "<" : "", query
? webQueryFile
: "");
159 unlink(webQueryFile
);
163 chmod(webExecFile
, 0700);
166 if ((f
= fdopen(fq
, "wb")) != NULL
) {
167 fprintf(f
, "%s\n", query
);
174 unlink(webQueryFile
);
180 sprintf(cmd
, "%s >%s 2>&1", webExecFile
, output
);
182 unlink(webQueryFile
);
186 static void wo_cgi_bin(char *url
)
188 char webOutpFile
[] = "/tmp/.woXXXXXX";
191 if ((fd
= mkstemp(webOutpFile
)) < 0)
195 _execute_command(url
, NULL
, post_buf
, webOutpFile
);
205 static void wo_shell(char *url
)
207 char webOutpFile
[] = "/tmp/.woXXXXXX";
210 if ((fd
= mkstemp(webOutpFile
)) < 0)
214 _execute_command(NULL
, webcgi_get("command"), NULL
, webOutpFile
);
216 web_puts("\ncmdresult = '");
217 web_putfile(webOutpFile
, WOF_JAVASCRIPT
);
222 static void wo_blank(char *url
)
224 web_puts("\n\n\n\n");
227 static void wo_favicon(char *url
)
229 send_header(200, NULL
, "image/vnd.microsoft.icon", 0);
232 if (nvram_match("web_favicon", "1")) {
233 send_header(200, NULL, "image/vnd.microsoft.icon", 0);
237 send_error(404, NULL, NULL);
242 static void wo_cfe(char *url
)
244 do_file(MTD_DEV(0ro
));
247 static void wo_nvram(char *url
)
249 web_pipecmd("nvram show", WOF_NONE
);
252 static void wo_iptables(char *url
)
254 web_pipecmd("iptables -nvL; iptables -t nat -nvL; iptables -t mangle -nvL", WOF_NONE
);
258 static void wo_spin(char *url)
262 strlcpy(s, nvram_safe_get("web_css"), sizeof(s));
263 strlcat(s, "_spin.gif", sizeof(s));
264 if (f_exists(s)) do_file(s);
265 else do_file("_spin.gif");
269 void common_redirect(void)
271 if (atoi(webcgi_safeget("_ajax", ""))) {
272 send_header(200, NULL
, mime_html
, 0);
276 redirect(webcgi_safeget("_redirect", "/"));
280 // ----------------------------------------------------------------------------
282 const struct mime_handler mime_handlers
[] = {
283 { "update.cgi", mime_javascript
, 0, wi_generic
, wo_update
, 1 },
284 { "tomato.cgi", NULL
, 0, wi_generic
, wo_tomato
, 1 },
286 { "debug.js", mime_javascript
, 5, wi_generic_noid
, wo_blank
, 1 }, // while debugging
287 { "cfe/*.bin", mime_binary
, 0, wi_generic
, wo_cfe
, 1 },
288 { "nvram/*.txt", mime_binary
, 0, wi_generic
, wo_nvram
, 1 },
289 { "ipt/*.txt", mime_binary
, 0, wi_generic
, wo_iptables
, 1 },
291 { "cfg/*.cfg", NULL
, 0, wi_generic
, wo_backup
, 1 },
292 { "cfg/restore.cgi", mime_html
, 0, wi_restore
, wo_restore
, 1 },
293 { "cfg/defaults.cgi", NULL
, 0, wi_generic
, wo_defaults
, 1 },
295 { "bwm/*.gz", NULL
, 0, wi_generic
, wo_bwmbackup
, 1 },
296 { "bwm/restore.cgi", NULL
, 0, wi_bwmrestore
, wo_bwmrestore
, 1 },
298 { "logs/view.cgi", NULL
, 0, wi_generic
, wo_viewlog
, 1 },
299 { "logs/*.txt", NULL
, 0, wi_generic
, wo_syslog
, 1 },
301 { "logout.asp", NULL
, 0, wi_generic
, wo_asp
, 1 },
302 { "clearcookies.asp", NULL
, 0, wi_generic
, wo_asp
, 1 },
304 // { "spin.gif", NULL, 0, wi_generic_noid, wo_spin, 1 },
306 { "**.asp", NULL
, 0, wi_generic_noid
, wo_asp
, 1 },
307 { "**.css", "text/css", 2, wi_generic_noid
, do_file
, 1 },
308 { "**.htm", mime_html
, 2, wi_generic_noid
, do_file
, 1 },
309 { "**.gif", "image/gif", 5, wi_generic_noid
, do_file
, 1 },
310 { "**.jpg", "image/jpeg", 5, wi_generic_noid
, do_file
, 1 },
311 { "**.png", "image/png", 5, wi_generic_noid
, do_file
, 1 },
312 { "**.js", mime_javascript
, 2, wi_generic_noid
, do_file
, 1 },
313 { "**.jsx", mime_javascript
, 0, wi_generic
, wo_asp
, 1 },
314 { "**.svg", "image/svg+xml", 2, wi_generic_noid
, do_file
, 1 },
315 { "**.txt", mime_plain
, 2, wi_generic_noid
, do_file
, 1 },
316 { "**.bin", mime_binary
, 0, wi_generic_noid
, do_file
, 1 },
317 { "**.bino", mime_octetstream
, 0, wi_generic_noid
, do_file
, 1 },
318 { "favicon.ico", NULL
, 5, wi_generic_noid
, wo_favicon
, 1 },
319 // !!TB - CGI Support, enable downloading archives
320 { "**/cgi-bin/**|**.sh", NULL
, 0, wi_cgi_bin
, wo_cgi_bin
, 1 },
321 { "**.tar|**.gz", mime_binary
, 0, wi_generic_noid
, do_file
, 1 },
322 { "shell.cgi", mime_javascript
, 0, wi_generic
, wo_shell
, 1 },
324 { "dhcpc.cgi", NULL
, 0, wi_generic
, wo_dhcpc
, 1 },
325 { "dhcpd.cgi", mime_javascript
, 0, wi_generic
, wo_dhcpd
, 1 },
326 { "nvcommit.cgi", NULL
, 0, wi_generic
, wo_nvcommit
, 1 },
327 { "ping.cgi", mime_javascript
, 0, wi_generic
, wo_ping
, 1 },
328 { "trace.cgi", mime_javascript
, 0, wi_generic
, wo_trace
, 1 },
329 { "upgrade.cgi", mime_html
, 0, wi_upgrade
, wo_flash
, 1 },
330 { "upnp.cgi", NULL
, 0, wi_generic
, wo_upnp
, 1 },
331 { "wakeup.cgi", NULL
, 0, wi_generic
, wo_wakeup
, 1 },
332 { "wlmnoise.cgi", mime_html
, 0, wi_generic
, wo_wlmnoise
, 1 },
333 { "wlradio.cgi", NULL
, 0, wi_generic
, wo_wlradio
, 1 },
334 { "resolve.cgi", mime_javascript
, 0, wi_generic
, wo_resolve
, 1 },
335 { "expct.cgi", mime_html
, 0, wi_generic
, wo_expct
, 1 },
336 { "service.cgi", NULL
, 0, wi_generic
, wo_service
, 1 },
337 // { "logout.cgi", NULL, 0, wi_generic, wo_logout, 0 }, // see httpd.c
338 { "shutdown.cgi", mime_html
, 0, wi_generic
, wo_shutdown
, 1 },
339 #ifdef TCONFIG_OPENVPN
340 { "vpnstatus.cgi", mime_javascript
, 0, wi_generic
, wo_vpn_status
, 1 },
343 { "usbcmd.cgi", mime_javascript
, 0, wi_generic
, wo_usbcommand
, 1 }, //!!TB - USB
346 { "blackhole.cgi", NULL
, 0, wi_blackhole
, NULL
, 1 },
348 // { "test", mime_html, 0, wi_generic, wo_test, 1 },
349 { NULL
, NULL
, 0, NULL
, NULL
, 1 }
352 const aspapi_t aspapi
[] = {
353 { "activeroutes", asp_activeroutes
},
354 { "arplist", asp_arplist
},
355 { "bandwidth", asp_bandwidth
},
356 { "build_time", asp_build_time
},
357 { "cgi_get", asp_cgi_get
},
358 { "compmac", asp_compmac
},
359 { "ctcount", asp_ctcount
},
360 { "ctdump", asp_ctdump
},
361 { "ddnsx", asp_ddnsx
},
362 { "devlist", asp_devlist
},
363 { "dhcpc_time", asp_dhcpc_time
},
365 { "ident", asp_ident
},
366 { "lanip", asp_lanip
},
367 { "layer7", asp_layer7
},
368 { "link_uptime", asp_link_uptime
},
369 { "lipp", asp_lipp
},
370 { "netdev", asp_netdev
},
371 { "notice", asp_notice
},
373 { "nvram", asp_nvram
},
374 { "nvramseq", asp_nvramseq
},
375 { "psup", asp_psup
},
376 { "qrate", asp_qrate
},
377 { "resmsg", asp_resmsg
},
378 { "rrule", asp_rrule
},
379 { "statfs", asp_statfs
},
380 { "sysinfo", asp_sysinfo
},
381 { "time", asp_time
},
382 { "upnpinfo", asp_upnpinfo
},
383 { "version", asp_version
},
384 { "wanstatus", asp_wanstatus
},
385 { "wanup", asp_wanup
},
386 { "wlchannel", asp_wlchannel
},
387 { "wlclient", asp_wlclient
},
388 { "wlcrssi", asp_wlcrssi
},
389 { "wlnoise", asp_wlnoise
},
390 { "wlnbw", asp_wlnbw
},
391 { "wlnctrlsb", asp_wlnctrlsb
},
392 { "wlradio", asp_wlradio
},
393 { "wlscan", asp_wlscan
},
394 { "wlchannels", asp_wlchannels
}, //!!TB
396 { "usbdevices", asp_usbdevices
}, //!!TB - USB Support
402 // -----------------------------------------------------------------------------
404 static void asp_css(int argc
, char **argv
)
406 const char *css
= nvram_safe_get("web_css");
408 if (strcmp(css
, "tomato") != 0) {
409 web_printf("<link rel='stylesheet' type='text/css' href='%s.css'>", css
);
413 // -----------------------------------------------------------------------------
415 const char *resmsg_get(void)
417 return webcgi_safeget("resmsg", "");
420 void resmsg_set(const char *msg
)
422 webcgi_set("resmsg", strdup(msg
)); // m ok
425 int resmsg_fread(const char *fname
)
430 f_read_string(fname
, s
, sizeof(s
));
431 if ((p
= strchr(s
, '\n')) != NULL
) *p
= 0;
439 static void asp_resmsg(int argc
, char **argv
)
443 if ((p
= js_string(webcgi_safeget("resmsg", (argc
> 0) ? argv
[0] : ""))) == NULL
) return;
444 web_printf("\nresmsg='%s';\n", p
);
448 // ----------------------------------------------------------------------------
450 // verification... simple sanity checks. UI should verify all fields.
452 // todo: move and re-use for filtering - zzz
463 VT_NONE
, // no checking
464 VT_LENGTH
, // check length of string
465 VT_TEXT
, // strip \r, check length of string
466 VT_RANGE
, // expect an integer, check range
467 VT_IP
, // expect an ip address
468 VT_MAC
, // expect a mac address
469 VT_TEMP
// no checks, no commit
476 #define V_NONE VT_NONE, { }, { }
477 #define V_01 VT_RANGE, { .l = 0 }, { .l = 1 }
478 #define V_PORT VT_RANGE, { .l = 2 }, { .l = 65535 }
479 #define V_ONOFF VT_LENGTH, { .i = 2 }, { .i = 3 }
480 #define V_WORD VT_LENGTH, { .i = 1 }, { .i = 16 }
481 #define V_LENGTH(min, max) VT_LENGTH, { .i = min }, { .i = max }
482 #define V_TEXT(min, max) VT_TEXT, { .i = min }, { .i = max }
483 #define V_RANGE(min, max) VT_RANGE, { .l = min }, { .l = max }
484 #define V_IP VT_IP, { }, { }
485 #define V_OCTET VT_RANGE, { .l = 0 }, { .l = 255 }
486 #define V_NUM VT_RANGE, { .l = 0 }, { .l = 0x7FFFFFFF }
487 #define V_TEMP VT_TEMP, { }, { }
489 static const nvset_t nvset_list
[] = {
492 { "router_name", V_LENGTH(0, 32) },
493 { "wan_hostname", V_LENGTH(0, 32) },
494 { "wan_domain", V_LENGTH(0, 32) },
497 { "tm_tz", V_LENGTH(1, 64) }, // PST8PDT
498 { "tm_sel", V_LENGTH(1, 64) }, // PST8PDT
500 { "ntp_updates", V_RANGE(-1, 24) },
501 { "ntp_tdod", V_01
},
502 { "ntp_server", V_LENGTH(1, 150) }, // x y z
503 { "ntp_kiss", V_LENGTH(0, 255) },
506 { "dhcpd_static", V_LENGTH(0, 106*101)}, // 106 (max chars per entry) x 100 entries
509 { "ddnsx0", V_LENGTH(0, 2048) },
510 { "ddnsx1", V_LENGTH(0, 2048) },
511 { "ddnsx0_cache", V_LENGTH(0, 1) }, // only to clear
512 { "ddnsx1_cache", V_LENGTH(0, 1) },
513 { "ddnsx_ip", V_LENGTH(0, 32) },
514 { "ddnsx_save", V_01
},
515 { "ddnsx_refresh", V_RANGE(0, 365) },
519 { "wan_proto", V_LENGTH(1, 16) }, // disabled, dhcp, static, pppoe, pptp, l2tp
520 { "wan_ipaddr", V_IP
},
521 { "wan_netmask", V_IP
},
522 { "wan_gateway", V_IP
},
523 { "hb_server_ip", V_LENGTH(0, 32) },
524 { "l2tp_server_ip", V_IP
},
525 { "pptp_server_ip", V_IP
},
526 { "ppp_username", V_LENGTH(0, 50) },
527 { "ppp_passwd", V_LENGTH(0, 50) },
528 { "ppp_service", V_LENGTH(0, 50) },
529 { "ppp_demand", V_01
},
530 { "ppp_idletime", V_RANGE(0, 1440) },
531 { "ppp_redialperiod", V_RANGE(1, 86400) },
532 { "mtu_enable", V_01
},
533 { "wan_mtu", V_RANGE(576, 1500) },
534 { "wan_islan", V_01
},
537 { "lan_ipaddr", V_IP
},
538 { "lan_netmask", V_IP
},
539 { "lan_gateway", V_IP
},
540 { "wan_dns", V_LENGTH(0, 50) }, // ip ip ip
541 { "lan_proto", V_WORD
}, // static, dhcp
542 { "dhcp_start", V_RANGE(1, 254) }, // remove !
543 { "dhcp_num", V_RANGE(1, 255) }, // remove !
544 { "dhcpd_startip", V_IP
},
545 { "dhcpd_endip", V_IP
},
546 { "dhcp_lease", V_RANGE(1, 10080) },
547 { "wan_wins", V_IP
},
550 { "wl_radio", V_01
},
551 { "wl_mode", V_LENGTH(2, 3) }, // ap, sta, wet, wds
552 { "wl_net_mode", V_LENGTH(5, 8) }, // disabled, mixed, b-only, g-only, bg-mixed, n-only [speedbooster]
553 { "wl_ssid", V_LENGTH(1, 32) },
554 { "wl_closed", V_01
},
555 { "wl_channel", V_RANGE(0, 14) }, //!!TB - 0=Auto
560 { "security_mode2", V_LENGTH(1, 32) }, // disabled, radius, wep, wpa_personal, wpa_enterprise, wpa2_personal, wpa2_enterprise
561 { "wl_radius_ipaddr", V_IP
},
562 { "wl_radius_port", V_PORT
},
563 { "wl_radius_key", V_LENGTH(1, 64) },
564 { "wl_wep_bit", V_RANGE(64, 128) }, // 64 or 128
565 { "wl_passphrase", V_LENGTH(0, 20) },
566 { "wl_key", V_RANGE(1, 4) },
567 { "wl_key1", V_LENGTH(0, 26) },
568 { "wl_key2", V_LENGTH(0, 26) },
569 { "wl_key3", V_LENGTH(0, 26) },
570 { "wl_key4", V_LENGTH(0, 26) },
571 { "wl_crypto", V_LENGTH(3, 8) }, // tkip, aes, tkip+aes
572 { "wl_wpa_psk", V_LENGTH(8, 64) },
573 { "wl_wpa_gtk_rekey", V_RANGE(60, 7200) },
575 { "wl_lazywds", V_01
},
576 { "wl_wds", V_LENGTH(0, 180) }, // mac mac mac (x 10)
578 { "security_mode", V_LENGTH(1, 32) }, // disabled, radius, wpa, psk,wep, wpa2, psk2, wpa wpa2, psk psk2
579 { "wds_enable", V_01
},
580 { "wl_gmode", V_RANGE(-1, 6) },
581 { "wl_wep", V_LENGTH(1, 32) }, // off, on, restricted,tkip,aes,tkip+aes
582 { "wl_akm", V_LENGTH(0, 32) }, // wpa, wpa2, psk, psk2, wpa wpa2, psk psk2, ""
583 { "wl_auth_mode", V_LENGTH(4, 6) }, // none, radius
585 { "wl_nmode", V_NONE
},
586 { "wl_nreqd", V_NONE
},
587 { "wl_nbw_cap", V_RANGE(0, 2) }, // 0 - 20MHz, 1 - 40MHz, 2 - Auto
588 { "wl_nbw", V_NONE
},
589 { "wl_mimo_preamble", V_WORD
}, // 802.11n Preamble: mm/gf/auto/gfbcm
590 { "wl_nctrlsb", V_NONE
}, // none, lower, upper
593 { "wl_macmode", V_NONE
}, // allow, deny, disabled
594 { "wl_maclist", V_LENGTH(0, 18*201) }, // 18 x 200 (11:22:33:44:55:66 ...)
595 { "macnames", V_LENGTH(0, 62*201) }, // 62 (12+1+48+1) x 50 (112233445566<..>) todo: re-use -- zzz
598 { "ct_max", V_RANGE(128, 300000) },
599 { "ct_tcp_timeout", V_LENGTH(20, 70) },
600 { "ct_udp_timeout", V_LENGTH(5, 15) },
601 { "ct_timeout", V_LENGTH(5, 15) },
602 { "nf_ttl", V_RANGE(-10, 10) },
606 { "ct_hashsize", V_RANGE(127, 65535) },
614 { "dhcpd_slt", V_RANGE(-1, 43200) }, // -1=infinite, 0=follow normal lease time, >=1 custom
615 { "dhcpd_dmdns", V_01
},
616 { "dhcpd_lmax", V_NUM
},
617 { "dhcpd_gwmode", V_NUM
},
618 { "dns_addget", V_01
},
619 { "dns_intcpt", V_01
},
620 { "dhcpc_minpkt", V_01
},
621 { "dnsmasq_custom", V_TEXT(0, 2048) },
622 // { "dnsmasq_norw", V_01 },
625 { "block_wan", V_01
},
626 { "multicast_pass", V_01
},
627 { "block_loopback", V_01
},
628 { "nf_loopback", V_NUM
},
629 { "ne_syncookies", V_01
},
632 { "wait_time", V_RANGE(3, 20) },
633 { "wan_speed", V_RANGE(0, 4) },
634 { "jumbo_frame_enable", V_01
}, // Jumbo Frames support (for RT-N16/WNR3500L)
635 { "jumbo_frame_size", V_RANGE(1, 9720) },
638 { "mac_wan", V_LENGTH(0, 17) },
639 { "mac_wl", V_LENGTH(0, 17) },
642 { "routes_static", V_LENGTH(0, 2048) },
643 { "lan_stp", V_RANGE(0, 1) },
644 { "wk_mode", V_LENGTH(1, 32) }, // gateway, router
646 { "dr_setting", V_RANGE(0, 3) },
647 { "dr_lan_tx", V_LENGTH(0, 32) },
648 { "dr_lan_rx", V_LENGTH(0, 32) },
649 { "dr_wan_tx", V_LENGTH(0, 32) },
650 { "dr_wan_rx", V_LENGTH(0, 32) },
654 { "wl_country", V_LENGTH(0, 64) }, // !!TB - Country code
655 { "wl_country_code", V_LENGTH(0, 4) }, // !!TB - Country code
656 { "wl_btc_mode", V_RANGE(0, 2) }, // !!TB - BT Coexistence Mode: 0 (disable), 1 (enable), 2 (preemption)
657 { "wl_afterburner", V_LENGTH(2, 4) }, // off, on, auto
659 { "wl_rateset", V_LENGTH(2, 7) }, // all, default, 12
660 { "wl_rate", V_RANGE(0, 54 * 1000 * 1000) },
661 { "wl_mrate", V_RANGE(0, 54 * 1000 * 1000) },
662 { "wl_gmode_protection",V_LENGTH(3, 4) }, // off, auto
663 { "wl_frameburst", V_ONOFF
}, // off, on
664 { "wl_bcn", V_RANGE(1, 65535) },
665 { "wl_dtim", V_RANGE(1, 255) },
666 { "wl_frag", V_RANGE(256, 2346) },
667 { "wl_rts", V_RANGE(0, 2347) },
668 { "wl_ap_isolate", V_01
},
669 { "wl_plcphdr", V_LENGTH(4, 5) }, // long, short
670 { "wl_antdiv", V_RANGE(0, 3) },
671 { "wl_txant", V_RANGE(0, 3) },
672 { "wl_txpwr", V_RANGE(0, 255) },
673 { "wl_wme", V_WORD
}, // auto, off, on
674 { "wl_wme_no_ack", V_ONOFF
}, // off, on
675 { "wl_wme_apsd", V_ONOFF
}, // off, on
676 { "wl_maxassoc", V_RANGE(0, 255) },
677 { "wl_distance", V_LENGTH(0, 5) }, // "", 1-99999
678 { "wlx_hpamp", V_01
},
679 { "wlx_hperx", V_01
},
680 { "wl_reg_mode", V_LENGTH(1, 3) }, // !!TB - Regulatory: off, h, d
682 { "wl_nmode_protection", V_WORD
, }, // off, auto
683 { "wl_nmcsidx", V_RANGE(-2, 32), }, // -2 - 32
686 { "dmz_enable", V_01
},
687 { "dmz_ipaddr", V_LENGTH(0, 15) },
688 { "dmz_sip", V_LENGTH(0, 512) },
691 { "upnp_enable", V_NUM
},
692 { "upnp_secure", V_01
},
693 { "upnp_port", V_RANGE(0, 65535) },
694 { "upnp_ssdp_interval", V_RANGE(10, 9999) },
695 { "upnp_mnp", V_01
},
696 { "upnp_clean", V_01
},
697 { "upnp_clean_interval", V_RANGE(60, 65535) },
698 { "upnp_clean_threshold", V_RANGE(0, 9999) },
699 { "upnp_min_port_int", V_PORT
},
700 { "upnp_max_port_int", V_PORT
},
701 { "upnp_min_port_ext", V_PORT
},
702 { "upnp_max_port_ext", V_PORT
},
703 #ifndef USE_MINIUPNPD
704 // { "upnp_config", V_01 },
705 { "upnp_max_age", V_RANGE(5, 9999) },
709 { "portforward", V_LENGTH(0, 4096) },
712 { "trigforward", V_LENGTH(0, 4096) },
715 // access restriction
716 { "rruleN", V_RANGE(0, 49) },
717 // { "rrule##", V_LENGTH(0, 2048) }, // in save_variables()
720 { "http_enable", V_01
},
721 { "https_enable", V_01
},
722 { "https_crt_save", V_01
},
723 { "https_crt_cn", V_LENGTH(0, 64) },
724 { "https_crt_gen", V_TEMP
},
725 { "remote_management", V_01
},
726 { "remote_mgt_https", V_01
},
727 { "http_lanport", V_PORT
},
728 { "https_lanport", V_PORT
},
729 { "web_wl_filter", V_01
},
730 // { "web_favicon", V_01 },
731 { "web_css", V_LENGTH(1, 32) },
732 { "http_wanport", V_PORT
},
733 { "telnetd_eas", V_01
},
734 { "telnetd_port", V_PORT
},
735 { "sshd_eas", V_01
},
736 { "sshd_pass", V_01
},
737 { "sshd_port", V_PORT
},
738 { "sshd_remote", V_01
},
739 { "sshd_forwarding", V_01
},
740 { "sshd_rport", V_PORT
},
741 { "sshd_authkeys", V_TEXT(0, 4096) },
742 { "rmgt_sip", V_LENGTH(0, 512) },
743 { "ne_shlimit", V_TEXT(1, 50) },
746 { "rstats_enable", V_01
},
747 { "rstats_path", V_LENGTH(0, 48) },
748 { "rstats_stime", V_RANGE(1, 168) },
749 { "rstats_offset", V_RANGE(1, 31) },
750 { "rstats_exclude", V_LENGTH(0, 64) },
751 { "rstats_sshut", V_01
},
752 { "rstats_bak", V_01
},
755 { "sesx_led", V_RANGE(0, 255) }, // amber, white, aoss
756 { "sesx_b0", V_RANGE(0, 5) }, // 0-5: toggle wireless, reboot, shutdown, script, usb unmount
757 { "sesx_b1", V_RANGE(0, 5) }, // "
758 { "sesx_b2", V_RANGE(0, 5) }, // "
759 { "sesx_b3", V_RANGE(0, 5) }, // "
760 { "sesx_script", V_TEXT(0, 1024) }, //
761 { "script_brau", V_TEXT(0, 1024) }, //
764 { "debug_nocommit", V_01
},
765 { "debug_cprintf", V_01
},
766 { "debug_cprintf_file", V_01
},
767 // { "debug_keepfiles", V_01 },
768 { "debug_ddns", V_01
},
769 { "debug_norestart", V_TEXT(0, 128) },
770 { "console_loglevel", V_RANGE(1, 8) },
771 { "t_cafree", V_01
},
772 { "t_hidelr", V_01
},
775 { "sch_rboot", V_TEXT(0, 64) },
776 { "sch_rcon", V_TEXT(0, 64) },
777 { "sch_c1", V_TEXT(0, 64) },
778 { "sch_c1_cmd", V_TEXT(0, 2048) },
779 { "sch_c2", V_TEXT(0, 64) },
780 { "sch_c2_cmd", V_TEXT(0, 2048) },
781 { "sch_c3", V_TEXT(0, 64) },
782 { "sch_c3_cmd", V_TEXT(0, 2048) },
785 { "script_init", V_TEXT(0, 4096) },
786 { "script_shut", V_TEXT(0, 4096) },
787 { "script_fire", V_TEXT(0, 8192) },
788 { "script_wanup", V_TEXT(0, 4096) },
791 { "log_remote", V_01
},
792 { "log_remoteip", V_IP
},
793 { "log_remoteport", V_PORT
},
794 { "log_file", V_01
},
795 { "log_limit", V_RANGE(0, 2400) },
796 { "log_in", V_RANGE(0, 3) },
797 { "log_out", V_RANGE(0, 3) },
798 { "log_mark", V_RANGE(0, 1440) },
799 { "log_events", V_TEXT(0, 32) }, // "acre,crond,ntp"
802 { "cifs1", V_LENGTH(1, 1024) },
803 { "cifs2", V_LENGTH(1, 1024) },
806 { "jffs2_on", V_01
},
807 { "jffs2_exec", V_LENGTH(0, 64) },
808 { "jffs2_format", V_01
},
812 { "usb_enable", V_01
},
813 { "usb_uhci", V_01
},
814 { "usb_ohci", V_01
},
815 { "usb_usb2", V_01
},
816 { "usb_storage", V_01
},
817 { "usb_printer", V_01
},
818 { "usb_printer_bidirect", V_01
},
819 { "usb_fs_ext3", V_01
},
820 { "usb_fs_fat", V_01
},
822 { "usb_fs_ntfs", V_01
},
824 { "usb_automount", V_01
},
825 { "script_usbhotplug", V_TEXT(0, 2048) },
826 { "script_usbmount", V_TEXT(0, 2048) },
827 { "script_usbumount", V_TEXT(0, 2048) },
832 { "ftp_enable", V_RANGE(0, 2) },
833 { "ftp_super", V_01
},
834 { "ftp_anonymous", V_RANGE(0, 3) },
835 { "ftp_dirlist", V_RANGE(0, 2) },
836 { "ftp_port", V_PORT
},
837 { "ftp_max", V_RANGE(0, 12) },
838 { "ftp_ipmax", V_RANGE(0, 12) },
839 { "ftp_staytimeout", V_RANGE(0, 65535) },
840 { "ftp_rate", V_RANGE(0, 99999) },
841 { "ftp_anonrate", V_RANGE(0, 99999) },
842 { "ftp_anonroot", V_LENGTH(0, 256) },
843 { "ftp_pubroot", V_LENGTH(0, 256) },
844 { "ftp_pvtroot", V_LENGTH(0, 256) },
845 { "ftp_users", V_LENGTH(0, 4096) },
846 { "ftp_custom", V_TEXT(0, 2048) },
847 { "ftp_sip", V_LENGTH(0, 512) },
848 { "ftp_limit", V_TEXT(1, 50) },
852 #ifdef TCONFIG_SAMBASRV
854 { "smbd_enable", V_RANGE(0, 2) },
855 { "smbd_wgroup", V_LENGTH(0, 20) },
856 { "smbd_master", V_01
},
857 { "smbd_wins", V_01
},
858 { "smbd_cpage", V_LENGTH(0, 4) },
859 { "smbd_cset", V_LENGTH(0, 20) },
860 { "smbd_loglevel", V_RANGE(0, 100) },
861 { "smbd_custom", V_TEXT(0, 2048) },
862 { "smbd_autoshare", V_RANGE(0, 3) },
863 { "smbd_shares", V_LENGTH(0, 4096) },
864 { "smbd_user", V_LENGTH(0, 50) },
865 { "smbd_passwd", V_LENGTH(0, 50) },
869 { "qos_enable", V_01
},
874 { "qos_icmp", V_01
},
875 { "qos_reset", V_01
},
876 { "qos_pfifo", V_01
}, // !!TB
877 { "qos_obw", V_RANGE(10, 999999) },
878 { "qos_ibw", V_RANGE(10, 999999) },
879 { "qos_orules", V_LENGTH(0, 4096) },
880 { "qos_default", V_RANGE(0, 9) },
881 { "qos_irates", V_LENGTH(0, 128) },
882 { "qos_orates", V_LENGTH(0, 128) },
884 { "ne_vegas", V_01
},
885 { "ne_valpha", V_NUM
},
886 { "ne_vbeta", V_NUM
},
887 { "ne_vgamma", V_NUM
},
889 #ifdef TCONFIG_OPENVPN
891 { "vpn_debug", V_01
},
892 { "vpn_server_eas", V_NONE
},
893 { "vpn_server_dns", V_NONE
},
894 { "vpn_server1_if", V_TEXT(3, 3) }, // tap, tun
895 { "vpn_server1_proto", V_TEXT(3, 10) }, // udp, tcp-server
896 { "vpn_server1_port", V_PORT
},
897 { "vpn_server1_firewall", V_TEXT(0, 8) }, // auto, external, custom
898 { "vpn_server1_crypt", V_TEXT(0, 6) }, // tls, secret, custom
899 { "vpn_server1_comp", V_TEXT(0, 8) }, // yes, no, adaptive
900 { "vpn_server1_cipher", V_TEXT(0, 16) },
901 { "vpn_server1_dhcp", V_01
},
902 { "vpn_server1_r1", V_IP
},
903 { "vpn_server1_r2", V_IP
},
904 { "vpn_server1_sn", V_IP
},
905 { "vpn_server1_nm", V_IP
},
906 { "vpn_server1_local", V_IP
},
907 { "vpn_server1_remote", V_IP
},
908 { "vpn_server1_reneg", V_RANGE(-1,2147483647)},
909 { "vpn_server1_hmac", V_RANGE(-1, 2) },
910 { "vpn_server1_plan", V_01
},
911 { "vpn_server1_ccd", V_01
},
912 { "vpn_server1_c2c", V_01
},
913 { "vpn_server1_ccd_excl", V_01
},
914 { "vpn_server1_ccd_val", V_NONE
},
915 { "vpn_server1_pdns", V_01
},
916 { "vpn_server1_rgw", V_01
},
917 { "vpn_server1_custom", V_NONE
},
918 { "vpn_server1_static", V_NONE
},
919 { "vpn_server1_ca", V_NONE
},
920 { "vpn_server1_crt", V_NONE
},
921 { "vpn_server1_key", V_NONE
},
922 { "vpn_server1_dh", V_NONE
},
923 { "vpn_server2_if", V_TEXT(3, 3) }, // tap, tun
924 { "vpn_server2_proto", V_TEXT(3, 10) }, // udp, tcp-server
925 { "vpn_server2_port", V_PORT
},
926 { "vpn_server2_firewall", V_TEXT(0, 8) }, // auto, external, custom
927 { "vpn_server2_crypt", V_TEXT(0, 6) }, // tls, secret, custom
928 { "vpn_server2_comp", V_TEXT(0, 8) }, // yes, no, adaptive
929 { "vpn_server2_cipher", V_TEXT(0, 16) },
930 { "vpn_server2_dhcp", V_01
},
931 { "vpn_server2_r1", V_IP
},
932 { "vpn_server2_r2", V_IP
},
933 { "vpn_server2_sn", V_IP
},
934 { "vpn_server2_nm", V_IP
},
935 { "vpn_server2_local", V_IP
},
936 { "vpn_server2_remote", V_IP
},
937 { "vpn_server2_reneg", V_RANGE(-1,2147483647)},
938 { "vpn_server2_hmac", V_RANGE(-1, 2) },
939 { "vpn_server2_plan", V_01
},
940 { "vpn_server2_pdns", V_01
},
941 { "vpn_server2_rgw", V_01
},
942 { "vpn_server2_custom", V_NONE
},
943 { "vpn_server2_ccd", V_01
},
944 { "vpn_server2_c2c", V_01
},
945 { "vpn_server2_ccd_excl", V_01
},
946 { "vpn_server2_ccd_val", V_NONE
},
947 { "vpn_server2_static", V_NONE
},
948 { "vpn_server2_ca", V_NONE
},
949 { "vpn_server2_crt", V_NONE
},
950 { "vpn_server2_key", V_NONE
},
951 { "vpn_server2_dh", V_NONE
},
952 { "vpn_client_eas", V_NONE
},
953 { "vpn_client1_if", V_TEXT(3, 3) }, // tap, tun
954 { "vpn_client1_bridge", V_01
},
955 { "vpn_client1_nat", V_01
},
956 { "vpn_client1_proto", V_TEXT(3, 10) }, // udp, tcp-server
957 { "vpn_client1_addr", V_NONE
},
958 { "vpn_client1_port", V_PORT
},
959 { "vpn_client1_retry", V_RANGE(-1,32767) }, // -1 infinite, 0 disabled, >= 1 custom
960 { "vpn_client1_firewall", V_TEXT(0, 6) }, // auto, custom
961 { "vpn_client1_crypt", V_TEXT(0, 6) }, // tls, secret, custom
962 { "vpn_client1_comp", V_TEXT(0, 8) }, // yes, no, adaptive
963 { "vpn_client1_cipher", V_TEXT(0, 16) },
964 { "vpn_client1_local", V_IP
},
965 { "vpn_client1_remote", V_IP
},
966 { "vpn_client1_nm", V_IP
},
967 { "vpn_client1_reneg", V_RANGE(-1,2147483647)},
968 { "vpn_client1_hmac", V_RANGE(-1, 2) },
969 { "vpn_client1_adns", V_RANGE(0, 3) },
970 { "vpn_client1_rgw", V_01
},
971 { "vpn_client1_gw", V_TEXT(0, 15) },
972 { "vpn_client1_custom", V_NONE
},
973 { "vpn_client1_static", V_NONE
},
974 { "vpn_client1_ca", V_NONE
},
975 { "vpn_client1_crt", V_NONE
},
976 { "vpn_client1_key", V_NONE
},
977 { "vpn_client2_if", V_TEXT(3, 3) }, // tap, tun
978 { "vpn_client2_bridge", V_01
},
979 { "vpn_client2_nat", V_01
},
980 { "vpn_client2_proto", V_TEXT(3, 10) }, // udp, tcp-server
981 { "vpn_client2_addr", V_NONE
},
982 { "vpn_client2_port", V_PORT
},
983 { "vpn_client2_retry", V_RANGE(-1,32767) }, // -1 infinite, 0 disabled, >= 1 custom
984 { "vpn_client2_firewall", V_TEXT(0, 6) }, // auto, custom
985 { "vpn_client2_crypt", V_TEXT(0, 6) }, // tls, secret, custom
986 { "vpn_client2_comp", V_TEXT(0, 8) }, // yes, no, adaptive
987 { "vpn_client2_cipher", V_TEXT(0, 16) },
988 { "vpn_client2_local", V_IP
},
989 { "vpn_client2_remote", V_IP
},
990 { "vpn_client2_nm", V_IP
},
991 { "vpn_client2_reneg", V_RANGE(-1,2147483647)},
992 { "vpn_client2_hmac", V_RANGE(-1, 2) },
993 { "vpn_client2_adns", V_RANGE(0, 3) },
994 { "vpn_client2_rgw", V_01
},
995 { "vpn_client2_gw", V_TEXT(0, 15) },
996 { "vpn_client2_custom", V_NONE
},
997 { "vpn_client2_static", V_NONE
},
998 { "vpn_client2_ca", V_NONE
},
999 { "vpn_client2_crt", V_NONE
},
1000 { "vpn_client2_key", V_NONE
},
1022 port_flow_control_1 0,1
1023 port_rate_limit_1 0-8
1025 port_flow_control_2 0,1
1026 port_rate_limit_2 0-8
1028 port_flow_control_3 0,1
1029 port_rate_limit_3 0-8
1031 port_flow_control_4 0,1
1032 port_rate_limit_4 0-8
1040 static int save_variables(int write
)
1050 static const char *msgf
= "The field \"%s\" is invalid. Please report this problem.";
1053 for (v
= nvset_list
; v
->name
; ++v
) {
1054 // _dprintf("[%s] %p\n", v->name, webcgi_get((char*)v->name));
1055 if ((p
= webcgi_get((char*)v
->name
)) == NULL
) continue;
1059 p
= unix_string(p
); // NOTE: p = malloc'd
1063 if ((n
< v
->va
.i
) || (n
> v
->vb
.i
)) ok
= 0;
1066 l
= strtol(p
, &e
, 10);
1067 if ((p
== e
) || (*e
) || (l
< v
->va
.l
) || (l
> v
->vb
.l
)) ok
= 0;
1070 if ((sscanf(p
, "%3u.%3u.%3u.%3u", &u
[0], &u
[1], &u
[2], &u
[3]) != 4) ||
1071 (u
[0] > 255) || (u
[1] > 255) || (u
[2] > 255) || (u
[3] > 255)) ok
= 0;
1074 if ((sscanf(p
, "%2x:%2x:%2x:%2x:%2x:%2x", &u
[0], &u
[1], &u
[2], &u
[3], &u
[4], &u
[5]) != 6) ||
1075 (u
[0] > 255) || (u
[1] > 255) || (u
[2] > 255) || (u
[3] > 255) || (u
[4] > 255) || (u
[5] > 255)) ok
= 0;
1082 if (v
->vtype
== VT_TEXT
) free(p
);
1084 sprintf(s
, msgf
, v
->name
);
1089 if (!nvram_match((char *)v
->name
, p
)) {
1090 if (v
->vtype
!= VT_TEMP
) dirty
= 1;
1091 nvram_set(v
->name
, p
);
1094 if (v
->vtype
== VT_TEXT
) free(p
);
1101 if (((p1
= webcgi_get("set_password_1")) != NULL
) && (strcmp(p1
, "**********") != 0)) {
1102 if (((p2
= webcgi_get("set_password_2")) != NULL
) && (strcmp(p1
, p2
) == 0)) {
1103 if ((write
) && (!nvram_match("http_passwd", p1
))) {
1105 nvram_set("http_passwd", p1
);
1109 sprintf(s
, msgf
, "password");
1115 for (n
= 0; n
< 50; ++n
) {
1116 sprintf(s
, "rrule%d", n
);
1117 if ((p
= webcgi_get(s
)) != NULL
) {
1118 if (strlen(p
) > 2048) {
1119 sprintf(s
, msgf
, s
);
1123 if ((write
) && (!nvram_match(s
, p
))) {
1130 return (write
) ? dirty
: 1;
1133 static void wo_tomato(char *url
)
1142 // _dprintf("tomato.cgi\n");
1144 red
= webcgi_safeget("_redirect", "");
1145 if (!*red
) send_header(200, NULL
, mime_html
, 0);
1147 commit
= atoi(webcgi_safeget("_commit", "1"));
1148 ajax
= atoi(webcgi_safeget("_ajax", "0"));
1150 nvset
= atoi(webcgi_safeget("_nvset", "1"));
1152 if (!save_variables(0)) {
1154 web_printf("@msg:%s", resmsg_get());
1157 parse_asp("error.asp");
1161 commit
= save_variables(1) && commit
;
1163 resmsg_set("Settings saved.");
1166 rboot
= atoi(webcgi_safeget("_reboot", "0"));
1168 parse_asp("reboot.asp");
1172 web_printf("@msg:%s", resmsg_get());
1174 else if (atoi(webcgi_safeget("_moveip", "0"))) {
1175 parse_asp("saved-moved.asp");
1178 parse_asp("saved.asp");
1183 _dprintf("commit from tomato.cgi\n");
1187 if ((v
= webcgi_get("_service")) != NULL
&& *v
!= 0) {
1189 if (ajax
) web_printf(" Some services are being restarted...");
1202 for (i
= atoi(webcgi_safeget("_sleep", "0")); i
> 0; --i
) sleep(1);
1204 if (*red
) redirect(red
);
1214 // ----------------------------------------------------------------------------
1217 static void wo_update(char *url
)
1219 const aspapi_t
*api
;
1225 if ((name
= webcgi_get("exec")) != NULL
) {
1226 for (api
= aspapi
; api
->name
; ++api
) {
1227 if (strcmp(api
->name
, name
) == 0) {
1228 for (argc
= 0; argc
< 16; ++argc
) {
1229 sprintf(s
, "arg%d", argc
);
1230 if ((argv
[argc
] = (char *)webcgi_get(s
)) == NULL
) break;
1232 api
->exec(argc
, argv
);
1239 static void wo_service(char *url
)
1243 exec_service(webcgi_safeget("_service", ""));
1245 if ((n
= atoi(webcgi_safeget("_sleep", "2"))) <= 0) n
= 2;
1251 static void wo_shutdown(char *url
)
1253 parse_asp("shutdown.asp");
1260 static void wo_nvcommit(char *url
)
1262 parse_asp("saved.asp");