summaryrefslogtreecommitdiff
path: root/release/src/router/httpd
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/httpd')
-rw-r--r--release/src/router/httpd/Makefile90
-rw-r--r--release/src/router/httpd/basic.c40
-rw-r--r--release/src/router/httpd/blackhole.c183
-rw-r--r--release/src/router/httpd/bwm.c161
-rw-r--r--release/src/router/httpd/cert.pem14
-rw-r--r--release/src/router/httpd/cgi.c103
-rw-r--r--release/src/router/httpd/config.c180
-rw-r--r--release/src/router/httpd/ctnf.c302
-rw-r--r--release/src/router/httpd/ddns.c90
-rw-r--r--release/src/router/httpd/devlist.c229
-rw-r--r--release/src/router/httpd/dhcp.c62
-rw-r--r--release/src/router/httpd/ej.c177
-rwxr-xr-xrelease/src/router/httpd/gencert.sh35
-rw-r--r--release/src/router/httpd/httpd.c1783
-rw-r--r--release/src/router/httpd/httpd.h194
-rw-r--r--release/src/router/httpd/key.pem9
-rw-r--r--release/src/router/httpd/log.c76
-rw-r--r--release/src/router/httpd/misc.c502
-rw-r--r--release/src/router/httpd/nvram.c70
-rw-r--r--release/src/router/httpd/openssl.cnf263
-rw-r--r--release/src/router/httpd/parser.c187
-rw-r--r--release/src/router/httpd/prebuilt/ezc.obin16732 -> 0 bytes
-rw-r--r--release/src/router/httpd/tomato.c935
-rw-r--r--release/src/router/httpd/tomato.h162
-rw-r--r--release/src/router/httpd/traceping.c108
-rw-r--r--release/src/router/httpd/upgrade.c153
-rw-r--r--release/src/router/httpd/upnp.c74
-rw-r--r--release/src/router/httpd/version.c24
-rw-r--r--release/src/router/httpd/webio.c229
-rw-r--r--release/src/router/httpd/webmsg.c65
-rw-r--r--release/src/router/httpd/wl.c247
31 files changed, 4926 insertions, 1821 deletions
diff --git a/release/src/router/httpd/Makefile b/release/src/router/httpd/Makefile
index 9e77c950..24e479f1 100644
--- a/release/src/router/httpd/Makefile
+++ b/release/src/router/httpd/Makefile
@@ -1,76 +1,42 @@
-#
-# milli_httpd Makefile
-#
-# Copyright 2005, Broadcom Corporation
-# All Rights Reserved.
-#
-# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-#
-# $Id: Makefile,v 1.40.18.1.2.2 2006/02/07 10:56:31 honor Exp $
-#
-include $(TOP)/.config
+include ../common.mak
-ifneq ($(wildcard $(SRCBASE)/cy_conf.mak),)
- include $(SRCBASE)/cy_conf.mak
-endif
+CFLAGS = -O2 -Wall
+CFLAGS += -I$(SRCBASE) -I$(SRCBASE)/include -I. -I$(TOP)/shared
-CFLAGS += -I. -I$(TOP)/shared -I$(SRCBASE)/include -Wall -I$(SRCBASE)/
+OBJS = httpd.o cgi.o tomato.o version.o
+OBJS += misc.o dhcp.o upgrade.o traceping.o parser.o upnp.o ctnf.o
+OBJS += nvram.o log.o webio.o wl.o devlist.o ddns.o config.o bwm.o
+OBJS += blackhole.o
-#CFLAGS += -g -DDEBUG
-CFLAGS += -s -O2
-LDFLAGS += -L$(TOP)/nvram -L$(INSTALLDIR)/nvram/usr/lib -lnvram -L$(TOP)/shared -L$(INSTALLDIR)/shared/usr/lib -lshared
+LIBS = -L../nvram -lnvram -L../shared -lshared
+LIBS += -L../mssl -lmssl
+all: httpd
-CFLAGS += -I$(TOP)/openssl/include -I$(TOP)/openssl/include/openssl
-LDFLAGS += -L$(TOP)/openssl -L../openssl -lcrypto -lssl
-OBJS += $(SRCBASE)/../tools/src/code_header.o backup_restore.o
-OBJS += setup_wizard.o
-OBJS += qos.o
+httpd: $(OBJS)
+ @echo " [httpd] CC $@"
+ @$(CC) -o $@ $(OBJS) $(LIBS)
+ $(SIZECHECK)
+ $(CPTMP)
-vpath %.c $(TOP)/shared
-vpath %.o $(SRCBASE)/router/httpd/prebuilt
-
-all:clean httpd
-
-clean:
- rm -f *.o *~ httpd
- rm -f $(SRCBASE)/../tools/src/code_header.o
-
install:
- install -D httpd $(INSTALLDIR)/usr/sbin/httpd
- $(STRIP) $(INSTALLDIR)/usr/sbin/httpd
- install -d $(INSTALLDIR)/etc
- #install *.pem $(INSTALLDIR)/etc
- install openssl.cnf $(INSTALLDIR)/etc
- install -m 755 gencert.sh $(INSTALLDIR)/usr/sbin
-
-cert:
- # create the key and certificate request
- openssl req -new -out cert.csr -config openssl.cnf -keyout privkey.pem -days 3650 -newkey rsa:512
- # remove the passphrase from the key:
- openssl rsa -in privkey.pem -out key.pem
- # convert the certificate request into a signed certificate
- openssl x509 -in cert.csr -out cert.pem -req -signkey key.pem
- rm -f cert.csr privkey.pem
- # Show human-readable format
- openssl x509 -in cert.pem -text -noout
+ @echo " [httpd] Installing to $(INSTALLDIR)"
+ @install -m 0500 -D httpd $(INSTALLDIR)/usr/sbin/httpd
+ @$(STRIP) $(INSTALLDIR)/usr/sbin/httpd
-#qos_1.o:qos.o interface.o
+clean:
+ rm -f httpd *.o .*.depend
-httpd: cgi.o ej.o httpd.o broadcom.o \
- index.o status.o dhcp.o log.o upgrade.o filters.o forward.o dynamic_route.o static_route.o wireless.o ddns.o \
- find_pattern.o lib.o diag.o sysinfo.o wepkey.o md5c.o wl_test.o getservice.o $(OBJS)
- $(CC) -o $@ $^ $(LDFLAGS)
+size: httpd
+ mipsel-uclibc-nm --print-size --size-sort httpd
-build_date.o: build_date.c
-build_date:
- echo "#define BUILD_DATE \"`date \"+%b %d %Y\"`\"" > build_date.c
- echo "#define BUILD_TIME \"`date \"+%H:%M:%S\"`\"" >> build_date.c
+%.o: %.c .%.depend
+ @echo " [httpd] CC $@"
+ @$(CC) $(CFLAGS) -o $@ -c $<
+.%.depend: %.c
+ @$(CC) $(CFLAGS) -M $< > $@
-*.o: $(CY_DEPS)
+-include $(OBJS:%.o=.%.depend)
diff --git a/release/src/router/httpd/basic.c b/release/src/router/httpd/basic.c
deleted file mode 100644
index 2eb88879..00000000
--- a/release/src/router/httpd/basic.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Basic skin (shtml)
- *
- * Copyright 2005, Broadcom Corporation
- * All Rights Reserved.
- *
- * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
- * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
- * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
- *
- * $Id: basic.c,v 1.1.1.7 2005/03/07 07:31:13 kanki Exp $
- */
-
-#include <stdio.h>
-#include <httpd.h>
-
-struct mime_handler mime_handlers[] = {
- { "**.htm", "text/html", NULL, NULL, do_file, NULL },
- { "**.html", "text/html", NULL, NULL, do_file, NULL },
- { "**.gif", "image/gif", NULL, NULL, do_file, NULL },
- { "**.jpg", "image/jpeg", NULL, NULL, do_file, NULL },
- { "**.jpeg", "image/gif", NULL, NULL, do_file, NULL },
- { "**.png", "image/png", NULL, NULL, do_file, NULL },
- { "**.css", "text/css", NULL, NULL, do_file, NULL },
- { "**.au", "audio/basic", NULL, NULL, do_file, NULL },
- { "**.wav", "audio/wav", NULL, NULL, do_file, NULL },
- { "**.avi", "video/x-msvideo", NULL, NULL, do_file, NULL },
- { "**.mov", "video/quicktime", NULL, NULL, do_file, NULL },
- { "**.mpeg", "video/mpeg", NULL, NULL, do_file, NULL },
- { "**.vrml", "model/vrml", NULL, NULL, do_file, NULL },
- { "**.midi", "audio/midi", NULL, NULL, do_file, NULL },
- { "**.mp3", "audio/mpeg", NULL, NULL, do_file, NULL },
- { "**.pac", "application/x-ns-proxy-autoconfig", NULL, NULL, do_file, NULL },
- { NULL, NULL, NULL, NULL, NULL, NULL }
-};
-
-struct ej_handler ej_handlers[] = {
- { NULL, NULL }
-};
diff --git a/release/src/router/httpd/blackhole.c b/release/src/router/httpd/blackhole.c
new file mode 100644
index 00000000..ab7df705
--- /dev/null
+++ b/release/src/router/httpd/blackhole.c
@@ -0,0 +1,183 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <time.h>
+
+
+#ifdef BLACKHOLE
+void wi_blackhole(char *url, int len, char *boundary)
+{
+ char buf[2048];
+ int size;
+ int n;
+ time_t tick;
+ int foo;
+ const char *error;
+ int blen;
+ FILE *f;
+
+ if (!post) {
+ send_header(200, NULL, mime_html, 0);
+ web_printf(
+ "<h1>Upload Test</h1>"
+ "<form method='post' action='blackhole.cgi?_http_id=%s' encType='multipart/form-data'>"
+ "<input type='file' name='file'><input type='submit'>"
+ "</form>",
+ nvram_safe_get("http_id"));
+ return;
+ }
+
+ check_id();
+
+ cprintf("\nblackhole\n");
+ cprintf("%s<\n", boundary);
+
+ if ((blen = strlen(boundary)) == 0) {
+ error = "no boundary";
+ERROR:
+ cprintf("ERROR: %s\n", error);
+
+ web_eat(len);
+
+ send_header(200, NULL, mime_html, 0);
+ web_printf("ERROR: %s", error);
+ return;
+ }
+
+ if (blen > (sizeof(buf) - 32)) {
+ error = "boundary is too big";
+ goto ERROR;
+ }
+
+ // --b\r\n
+ // <data>\r\n
+ // --b--\r\n
+ if (len < ((blen * 2) + 12)) {
+ error = "not enough data";
+ goto ERROR;
+ }
+
+ foo = 1;
+ while (len > 0) {
+ if (!web_getline(buf, MIN(len, sizeof(buf)))) {
+ break;
+ }
+ n = strlen(buf);
+ len -= n;
+
+ if (n < 2) {
+ error = "n < 2";
+ goto ERROR;
+ }
+ if (buf[--n] != '\n') {
+ error = "\\n not found";
+ goto ERROR;
+ }
+ if (buf[--n] != '\r') {
+ error = "\\n without \\r";
+ goto ERROR;
+ }
+ if (n == 0) break;
+ buf[n] = 0;
+
+ cprintf("%s<\n", buf);
+
+ if (foo) {
+ if ((buf[0] != '-') || (buf[1] != '-') || (strcmp(buf + 2, boundary) != 0)) {
+ error = "boundary not found on first line";
+ goto ERROR;
+ }
+ foo = 0;
+ }
+ }
+
+ if (foo != 0) {
+ error = "boundary not found before reaching end of header";
+ goto ERROR;
+ }
+
+ blen += 6;
+ len -= (blen + 2);
+ if (len < 0) {
+ error = "not enough data for end boundary";
+ goto ERROR;
+ }
+
+ unlink("/tmp/blackhole");
+/* if (len < (1*1024*1024)) f = fopen("/tmp/blackhole", "w");
+ else*/ f = NULL;
+
+#if 0
+ // read half, trigger tcp reset
+ len >>= 1;
+#endif
+
+ size = len;
+ tick = time(0);
+ while (len > 0) {
+ if ((n = web_read(buf, MIN(len, sizeof(buf)))) <= 0) {
+ break;
+ }
+ if (f) fwrite(buf, n, 1, f);
+ len -= n;
+ }
+ tick = time(0) - tick;
+ if (f) fclose(f);
+
+ if (len > 0) {
+ error = "not all data was read";
+ goto ERROR;
+ }
+
+ if (web_read(buf, blen) != blen) {
+ error = "error while reading end boundary";
+ goto ERROR;
+ }
+ buf[blen] = 0;
+ cprintf(">>%s<<\n", buf);
+ if ((strncmp(buf, "\r\n--", 4) != 0) ||
+ (buf[blen - 1] != '-') || (buf[blen - 2] != '-')
+ || (strncmp(buf + 4, boundary, blen - 6) != 0)) {
+ error = "end boundary not found";
+ goto ERROR;
+ }
+
+ len += 2;
+ if (len > 0) {
+ if ((n = web_read(buf, MIN(len, sizeof(buf) - 1))) > 0) {
+ len -= n;
+ buf[n] = 0;
+ cprintf("last >>%s<<\n", buf);
+ }
+ }
+
+ web_eat(len);
+ cprintf("len=%d\n", len);
+
+ if (tick > 0) n = size / tick;
+ else n = 0;
+
+ send_header(200, NULL, mime_html, 0);
+ web_printf(
+ "<pre>"
+ "Size .......: %d bytes\n"
+ "Time .......: %d seconds\n"
+ "Speed ......: %.2f kb/s | %.2f mb/s | %.2f KB/s | %.2f MB/s\n",
+ size,
+ tick,
+ n / 128.0, n / 131072.0,
+ n / 1024.0, n / 1048576.0);
+ if (f) {
+ web_pipecmd("md5sum /tmp/blackhole", WOF_NONE);
+ }
+ web_puts("</pre>");
+
+ cprintf("done...\n");
+}
+#endif
diff --git a/release/src/router/httpd/bwm.c b/release/src/router/httpd/bwm.c
new file mode 100644
index 00000000..b7e1732c
--- /dev/null
+++ b/release/src/router/httpd/bwm.c
@@ -0,0 +1,161 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <sys/stat.h>
+
+/*
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <typedefs.h>
+*/
+
+static const char *hfn = "/var/lib/misc/rstats-history.gz";
+
+void wo_bwmbackup(char *url)
+{
+ struct stat st;
+ time_t t;
+ int i;
+
+ if (stat(hfn, &st) == 0) {
+ t = st.st_mtime;
+ sleep(1);
+ }
+ else {
+ t = 0;
+ }
+ killall("rstats", SIGHUP);
+ for (i = 10; i > 0; --i) {
+ if ((stat(hfn, &st) == 0) && (st.st_mtime != t)) break;
+ sleep(1);
+ }
+ if (i == 0) {
+ send_error(500, NULL, NULL);
+ return;
+ }
+ send_header(200, NULL, mime_binary, 0);
+ do_file((char *)hfn);
+}
+
+void wi_bwmrestore(char *url, int len, char *boundary)
+{
+ char *buf;
+ const char *error;
+ int ok;
+ int n;
+ char tmp[64];
+
+ check_id(url);
+
+ tmp[0] = 0;
+ buf = NULL;
+ error = "Error reading file";
+ ok = 0;
+
+ if (!skip_header(&len)) {
+ goto ERROR;
+ }
+
+ if ((len < 64) || (len > 10240)) {
+ goto ERROR;
+ }
+
+ if ((buf = malloc(len)) == NULL) {
+ error = "Not enough memory";
+ goto ERROR;
+ }
+
+ n = web_read(buf, len);
+ len -= n;
+
+ sprintf(tmp, "%s.new", hfn);
+ if (f_write(tmp, buf, n, 0, 0600) != n) {
+ unlink(tmp);
+ error = "Error writing temporary file";
+ goto ERROR;
+ }
+ f_write("/var/tmp/rstats-load", NULL, 0, 0, 0600);
+ killall("rstats", SIGHUP);
+ sleep(1);
+
+ error = NULL;
+ rboot = 1; // used as "ok"
+
+ERROR:
+ free(buf);
+ web_eat(len);
+ if (error != NULL) resmsg_set(error);
+}
+
+void wo_bwmrestore(char *url)
+{
+ if (rboot) {
+ redirect("/bwm-daily.asp");
+ }
+ else {
+ parse_asp("error.asp");
+ }
+}
+
+void asp_netdev(int argc, char **argv)
+{
+ FILE *f;
+ char buf[256];
+ unsigned long rx, tx;
+ char *p;
+ char *ifname;
+ char comma;
+ char *exclude;
+
+ exclude = nvram_safe_get("rstats_exclude");
+ web_puts("\n\nnetdev={");
+ if ((f = fopen("/proc/net/dev", "r")) != NULL) {
+ fgets(buf, sizeof(buf), f); // header
+ fgets(buf, sizeof(buf), f); // "
+ comma = ' ';
+ while (fgets(buf, sizeof(buf), f)) {
+ if ((p = strchr(buf, ':')) == NULL) continue;
+ *p = 0;
+ if ((ifname = strrchr(buf, ' ')) == NULL) ifname = buf;
+ else ++ifname;
+// if (strncmp(ifname, "ppp", 3) == 0) ifname = "ppp";
+ if ((strcmp(ifname, "lo") == 0) || (find_word(exclude, ifname))) continue;
+
+ // <rx bytes, packets, errors, dropped, fifo errors, frame errors, compressed, multicast><tx ...>
+ if (sscanf(p + 1, "%lu%*u%*u%*u%*u%*u%*u%*u%lu", &rx, &tx) != 2) continue;
+ web_printf("%c'%s':{rx:0x%lx,tx:0x%lx}", comma, ifname, rx, tx);
+ comma = ',';
+ }
+ fclose(f);
+ }
+ web_puts("};\n");
+}
+
+void asp_bandwidth(int argc, char **argv)
+{
+ char *name;
+ int sig;
+
+ if ((nvram_get_int("rstats_enable") == 1) && (argc == 1)) {
+ if (strcmp(argv[0], "speed") == 0) {
+ sig = SIGUSR1;
+ name = "/var/spool/rstats-speed.js";
+ }
+ else {
+ sig = SIGUSR2;
+ name = "/var/spool/rstats-history.js";
+ }
+ unlink(name);
+ killall("rstats", sig);
+ f_wait_exists(name, 5);
+ do_file(name);
+ unlink(name);
+ }
+}
diff --git a/release/src/router/httpd/cert.pem b/release/src/router/httpd/cert.pem
deleted file mode 100644
index 4fc12f2e..00000000
--- a/release/src/router/httpd/cert.pem
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN CERTIFICATE-----
-MIICHDCCAcYCAQAwDQYJKoZIhvcNAQEEBQAwgZgxCzAJBgNVBAYTAlVTMRMwEQYD
-VQQIEwpDYWxpZm9ybmlhMQ8wDQYDVQQHEwZJcnZpbmUxGjAYBgNVBAoTEUNpc2Nv
-LUxpbmtzeXMsTENDMREwDwYDVQQLEwhEaXZpc2lvbjEQMA4GA1UEAxMHTGlua3N5
-czEiMCAGCSqGSIb3DQEJARYTc3VwcG9ydEBsaW5rc3lzLmNvbTAeFw0wNDA1MjAw
-NTI1MTBaFw0wNDA2MTkwNTI1MTBaMIGYMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
-Q2FsaWZvcm5pYTEPMA0GA1UEBxMGSXJ2aW5lMRowGAYDVQQKExFDaXNjby1MaW5r
-c3lzLExDQzERMA8GA1UECxMIRGl2aXNpb24xEDAOBgNVBAMTB0xpbmtzeXMxIjAg
-BgkqhkiG9w0BCQEWE3N1cHBvcnRAbGlua3N5cy5jb20wXDANBgkqhkiG9w0BAQEF
-AANLADBIAkEAvLeJgG1SIF0lP0caiBuK/2NEhX2oPJJX9VESl0eOkVn4KUkA2Vld
-qNBT14X02nfdfEz7D1BLE0y/CRFI5JX0iQIDAQABMA0GCSqGSIb3DQEBBAUAA0EA
-EEZKiLh5Xz7j64UBMIDXoxkNcgBFqO/+J2Sxv4seibnBFUam7z4peeq+6jJybaZF
-fZk8bkGdhtAUiAY6U8kv/Q==
------END CERTIFICATE-----
diff --git a/release/src/router/httpd/cgi.c b/release/src/router/httpd/cgi.c
index 6cc6293b..11176540 100644
--- a/release/src/router/httpd/cgi.c
+++ b/release/src/router/httpd/cgi.c
@@ -3,7 +3,7 @@
*
* Copyright 2005, Broadcom Corporation
* All Rights Reserved.
- *
+ *
* THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
* KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
* SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
@@ -12,123 +12,88 @@
* $Id: cgi.c,v 1.10 2005/03/07 08:35:32 kanki Exp $
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <shutils.h> //Added by Dainel(2004-07-26)
-#define assert(a)
+#include "tomato.h"
-#if defined(linux)
-/* Use SVID search */
#define __USE_GNU
#include <search.h>
-#endif
+
/* CGI hash table */
-static struct hsearch_data htab;
-static int htab_count;
+static struct hsearch_data htab = { .table = NULL };
-static void
-unescape(char *s)
+static void unescape(char *s)
{
unsigned int c;
while ((s = strpbrk(s, "%+"))) {
- /* Parse %xx */
if (*s == '%') {
sscanf(s + 1, "%02x", &c);
*s++ = (char) c;
- strncpy(s, s + 2, strlen(s) + 1);
+ strcpy(s, s + 2);
}
- /* Space is special */
- else if (*s == '+')
+ else if (*s == '+') {
*s++ = ' ';
+ }
}
}
-char *
-get_cgi(char *name)
+char *webcgi_get(const char *name)
{
ENTRY e, *ep;
- if (!htab.table)
- return NULL;
+ if (!htab.table) return NULL;
- e.key = name;
+ e.key = (char *)name;
hsearch_r(e, FIND, &ep, &htab);
+// cprintf("%s=%s\n", name, ep ? ep->data : "(null)");
+
return ep ? ep->data : NULL;
}
-void
-set_cgi(char *name, char *value)
+void webcgi_set(char *name, char *value)
{
ENTRY e, *ep;
- //cprintf("\nIn set_cgi(), name = %s, value = %s\n", name, value);
-
- if (!htab.table)
- return;
+ if (!htab.table) {
+ hcreate_r(16, &htab);
+ }
e.key = name;
hsearch_r(e, FIND, &ep, &htab);
- if (ep){
- //cprintf("\nIn set_cgi(), ep = %s\n", ep);
+ if (ep) {
ep->data = value;
- }
+ }
else {
- //cprintf("\nIn set_cgi(), ep = %s(NULL)\n", ep);
e.data = value;
hsearch_r(e, ENTER, &ep, &htab);
- htab_count++;
}
- assert(ep);
}
-void
-init_cgi(char *query)
+void webcgi_init(char *query)
{
- int len, nel;
- char *q, *name, *value;
+ int nel;
+ char *q, *end, *name, *value;
- htab_count = 0;
+ if (htab.table) hdestroy_r(&htab);
+ if (query == NULL) return;
- //cprintf("\nIn init_cgi(), query = %s\n", query);
-
- /* Clear variables */
- if (!query) {
- hdestroy_r(&htab);
- return;
- }
-
- /* Parse into individual assignments */
+// cprintf("query = %s\n", query);
+
+ end = query + strlen(query);
q = query;
- len = strlen(query);
nel = 1;
- while (strsep(&q, "&;"))
+ while (strsep(&q, "&;")) {
nel++;
+ }
hcreate_r(nel, &htab);
- //cprintf("\nIn init_cgi(), nel = %d\n", nel);
- for (q = query; q < (query + len);) {
- /* Unescape each assignment */
- unescape(name = value = q);
+ for (q = query; q < end; ) {
+ value = q;
+ q += strlen(q) + 1;
- /* Skip to next assignment */
- for (q += strlen(q); q < (query + len) && !*q; q++);
-
- /* Assign variable */
+ unescape(value);
name = strsep(&value, "=");
- if (value)
- set_cgi(name, value);
+ if (value) webcgi_set(name, value);
}
- //cprintf("\nIn init_cgi(), AFTER PROCESS query = %s\n", query);
-}
-
-int
-count_cgi()
-{
- return htab_count;
}
diff --git a/release/src/router/httpd/config.c b/release/src/router/httpd/config.c
new file mode 100644
index 00000000..52e4f5c5
--- /dev/null
+++ b/release/src/router/httpd/config.c
@@ -0,0 +1,180 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <typedefs.h>
+#include <sys/reboot.h>
+
+// #define DEBUG
+
+#ifdef DEBUG
+#define NVRAMCMD "/tmp/nvram"
+#else
+#define NVRAMCMD "nvram"
+#endif
+
+void wo_defaults(char *url)
+{
+ const char *v;
+ int mode;
+
+ if ((v = webcgi_get("mode")) != NULL) {
+ mode = atoi(v);
+ if ((mode == 1) || (mode == 2)) {
+ prepare_upgrade();
+
+ parse_asp("reboot-default.asp");
+ web_close();
+
+ killall("pppoecd", SIGTERM);
+
+ led(LED_DIAG, 1);
+ sleep(2);
+
+ if (mode == 1) {
+ // eval(NVRAMCMD, "defaults", "--yes");
+ nvram_set("restore_defaults", "1");
+ nvram_commit();
+ }
+ else {
+ eval("mtd-erase", "-d", "nvram");
+ }
+
+ set_action(ACT_REBOOT);
+ // kill(1, SIGTERM);
+ reboot(RB_AUTOBOOT);
+ exit(0);
+ }
+ }
+
+ redirect("/admin-config.asp");
+}
+
+void wo_backup(char *url)
+{
+ char tmp[64];
+ char msg[64];
+ static char *args[] = {
+ NVRAMCMD, "backup", NULL, NULL
+ };
+
+ strcpy(tmp, "/tmp/backupXXXXXX");
+ mktemp(tmp);
+ args[2] = tmp;
+
+ sprintf(msg, ">%s.msg", tmp);
+
+ if (_eval(args, msg, 0, NULL) == 0) {
+ send_header(200, NULL, mime_binary, 0);
+ do_file(tmp);
+ unlink(tmp);
+ }
+ else {
+ resmsg_fread(msg + 1);
+ send_header(200, NULL, mime_html, 0);
+ parse_asp("error.asp");
+ }
+
+ unlink(msg + 1);
+}
+
+void wi_restore(char *url, int len, char *boundary)
+{
+ char *buf;
+ const char *error;
+ int ok;
+ int n;
+ char tmp[64];
+
+ check_id(url);
+
+ tmp[0] = 0;
+ buf = NULL;
+ error = "Error reading file";
+ ok = 0;
+
+ if (!skip_header(&len)) {
+ goto ERROR;
+ }
+
+ if ((len < 64) || (len > (NVRAM_SPACE * 2))) {
+ error = "Invalid file";
+ goto ERROR;
+ }
+
+ if ((buf = malloc(len)) == NULL) {
+ error = "Not enough memory";
+ goto ERROR;
+ }
+
+ n = web_read(buf, len);
+ len -= n;
+
+ strcpy(tmp, "/tmp/restoreXXXXXX");
+ mktemp(tmp);
+ if (f_write(tmp, buf, n, 0, 0600) != n) {
+ error = "Error writing temporary file";
+ goto ERROR;
+ }
+
+ rboot = 1;
+ prepare_upgrade();
+
+ char msg[64];
+ static char *args[] = {
+ NVRAMCMD, "restore", NULL, NULL
+ };
+
+ args[2] = tmp;
+
+ sprintf(msg, ">%s.msg", tmp);
+
+ if (_eval(args, msg, 0, NULL) != 0) {
+ resmsg_fread(msg + 1);
+ }
+#ifndef DEBUG
+ unlink(msg + 1);
+#endif
+ error = NULL;
+
+ERROR:
+ free(buf);
+ if (error != NULL) resmsg_set(error);
+ web_eat(len);
+#ifndef DEBUG
+ if (tmp[0]) unlink(tmp);
+#endif
+}
+
+
+void wo_restore(char *url)
+{
+ if (rboot) {
+ parse_asp("reboot.asp");
+ web_close();
+
+ killall("pppoecd", SIGTERM);
+ sleep(2);
+
+#ifdef DEBUG
+ cprintf("---reboot=%d\n", rboot);
+#else
+ set_action(ACT_REBOOT);
+ // kill(1, SIGTERM);
+ sync();
+ reboot(RB_AUTOBOOT);
+#endif
+ exit(0);
+ }
+
+ parse_asp("error.asp");
+}
diff --git a/release/src/router/httpd/ctnf.c b/release/src/router/httpd/ctnf.c
new file mode 100644
index 00000000..f65aa35c
--- /dev/null
+++ b/release/src/router/httpd/ctnf.c
@@ -0,0 +1,302 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <ctype.h>
+#include <sys/sysinfo.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <time.h>
+#include <dirent.h>
+
+
+static void ctvbuf(FILE *f)
+{
+ int n;
+ struct sysinfo si;
+// meminfo_t mem;
+
+#if 1
+ const char *p;
+
+ if ((p = nvram_get("ct_max")) != NULL) {
+ n = atoi(p);
+ if (n == 0) n = 2048;
+ else if (n < 1024) n = 1024;
+ else if (n > 10240) n = 10240;
+ }
+ else {
+ n = 2048;
+ }
+#else
+ char s[64];
+
+ if (f_read_string("/proc/sys/net/ipv4/ip_conntrack_max", s, sizeof(s)) > 0) n = atoi(s);
+ else n = 1024;
+ if (n < 1024) n = 1024;
+ else if (n > 10240) n = 10240;
+#endif
+
+ n *= 170; // avg tested
+
+// get_memory(&mem);
+// if (mem.maxfreeram < (n + (64 * 1024))) n = mem.maxfreeram - (64 * 1024);
+
+ sysinfo(&si);
+ if (si.freeram < (n + (64 * 1024))) n = si.freeram - (64 * 1024);
+
+// cprintf("free: %dK, buffer: %dK\n", si.freeram / 1024, n / 1024);
+
+ if (n > 4096) {
+// n =
+ setvbuf(f, NULL, _IOFBF, n);
+// cprintf("setvbuf = %d\n", n);
+ }
+}
+
+void asp_ctcount(int argc, char **argv)
+{
+ static const char *states[10] = {
+ "NONE", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT",
+ "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN" };
+ int count[13]; // tcp(10) + udp(2) + total(1) = 13 / max classes = 10
+ FILE *f;
+ char s[512];
+ char *p;
+ int i;
+ int n;
+ int mode;
+ unsigned long rip;
+ unsigned long lan;
+ unsigned long mask;
+
+ if (argc != 1) return;
+ mode = atoi(argv[0]);
+
+ memset(count, 0, sizeof(count));
+
+ if ((f = fopen("/proc/net/ip_conntrack", "r")) != NULL) {
+ ctvbuf(f); // if possible, read in one go
+
+ if (nvram_match("t_hidelr", "1")) {
+ mask = inet_addr(nvram_safe_get("lan_netmask"));
+ rip = inet_addr(nvram_safe_get("lan_ipaddr"));
+ lan = rip & mask;
+ }
+ else {
+ rip = lan = mask = 0;
+ }
+
+ while (fgets(s, sizeof(s), f)) {
+ if (rip != 0) {
+ // src=x.x.x.x dst=x.x.x.x // DIR_ORIGINAL
+ if ((p = strstr(s + 14, "src=")) == NULL) continue;
+ if ((inet_addr(p + 4) & mask) == lan) {
+ if ((p = strstr(p + 13, "dst=")) == NULL) continue;
+ if (inet_addr(p + 4) == rip) continue;
+ }
+ }
+
+ if (mode == 0) {
+ // count connections per state
+ if (strncmp(s, "tcp", 3) == 0) {
+ for (i = 9; i >= 0; --i) {
+ if (strstr(s, states[i]) != NULL) {
+ count[i]++;
+ break;
+ }
+ }
+ }
+ else if (strncmp(s, "udp", 3) == 0) {
+ if (strstr(s, "[UNREPLIED]") != NULL) {
+ count[10]++;
+ }
+ else if (strstr(s, "[ASSURED]") != NULL) {
+ count[11]++;
+ }
+ }
+ count[12]++;
+ }
+ else {
+ // count connections per mark
+ if ((p = strstr(s, " mark=")) != NULL) {
+ n = atoi(p + 6) & 0xFF;
+ if (n <= 10) count[n]++;
+ }
+ }
+ }
+
+ fclose(f);
+ }
+
+ if (mode == 0) {
+ p = s;
+ for (i = 0; i < 12; ++i) {
+ p += sprintf(p, ",%d", count[i]);
+ }
+ web_printf("\nconntrack = [%d%s];\n", count[12], s);
+ }
+ else {
+ p = s;
+ for (i = 1; i < 11; ++i) {
+ p += sprintf(p, ",%d", count[i]);
+ }
+ web_printf("\nnfmarks = [%d%s];\n", count[0], s);
+ }
+}
+
+void asp_ctdump(int argc, char **argv)
+{
+ FILE *f;
+ char s[512];
+ char *p, *q;
+ int mark;
+ int findmark;
+ unsigned int proto;
+ unsigned int time;
+ char src[16];
+ char dst[16];
+ char sport[16];
+ char dport[16];
+ unsigned long rip;
+ unsigned long lan;
+ unsigned long mask;
+ char comma;
+
+ if (argc != 1) return;
+
+ findmark = atoi(argv[0]);
+
+ mask = inet_addr(nvram_safe_get("lan_netmask"));
+ rip = inet_addr(nvram_safe_get("lan_ipaddr"));
+ lan = rip & mask;
+ if (nvram_match("t_hidelr", "0")) rip = 0; // hide lan -> router?
+
+ web_puts("\nctdump = [");
+ comma = ' ';
+ if ((f = fopen("/proc/net/ip_conntrack", "r")) != NULL) {
+ ctvbuf(f);
+ while (fgets(s, sizeof(s), f)) {
+ if ((p = strstr(s, " mark=")) == NULL) continue;
+ if ((mark = (atoi(p + 6) & 0xFF)) > 10) mark = 0;
+ if ((findmark != -1) && (mark != findmark)) continue;
+
+ if (sscanf(s, "%*s %u %u", &proto, &time) != 2) continue;
+
+ if ((p = strstr(s + 14, "src=")) == NULL) continue; // DIR_ORIGINAL
+ if ((inet_addr(p + 4) & mask) != lan) {
+ // make sure we're seeing int---ext if possible
+ if ((p = strstr(p + 41, "src=")) == NULL) continue; // DIR_REPLY
+ }
+ else if (rip != 0) {
+ if ((q = strstr(p + 13, "dst=")) == NULL) continue;
+// cprintf("%lx=%lx\n", inet_addr(q + 4), rip);
+ if (inet_addr(q + 4) == rip) continue;
+ }
+
+ if ((proto == 6) || (proto == 17)) {
+ if (sscanf(p + 4, "%s dst=%s sport=%s dport=%s", src, dst, sport, dport) != 4) continue;
+ }
+ else {
+ if (sscanf(p + 4, "%s dst=%s", src, dst) != 2) continue;
+ sport[0] = 0;
+ dport[0] = 0;
+ }
+
+ web_printf("%c[%u,%u,'%s','%s','%s','%s',%d]", comma, proto, time, src, dst, sport, dport, mark);
+ comma = ',';
+ }
+ }
+ web_puts("];\n");
+}
+
+void asp_qrate(int argc, char **argv)
+{
+ FILE *f;
+ char s[256];
+ unsigned long rates[10];
+ unsigned long u;
+ char *e;
+ int n;
+ char comma;
+ char *a[1];
+
+ a[0] = "1";
+ asp_ctcount(1, a);
+
+ memset(rates, 0, sizeof(rates));
+ sprintf(s, "tc -s class ls dev %s", nvram_safe_get("wan_iface"));
+ if ((f = popen(s, "r")) != NULL) {
+ n = 1;
+ while (fgets(s, sizeof(s), f)) {
+ if (strncmp(s, "class htb 1:", 12) == 0) {
+ n = atoi(s + 12);
+ }
+ else if (strncmp(s, " rate ", 6) == 0) {
+ if ((n % 10) == 0) {
+ n /= 10;
+ if ((n >= 1) && (n <= 10)) {
+ u = strtoul(s + 6, &e, 10);
+ if (*e == 'K') u *= 1000;
+ else if (*e == 'M') u *= 1000 * 1000;
+ rates[n - 1] = u;
+ n = 1;
+ }
+ }
+ }
+ }
+ pclose(f);
+ }
+
+ comma = ' ';
+ web_puts("\nqrates = [0,");
+ for (n = 0; n < 10; ++n) {
+ web_printf("%c%lu", comma, rates[n]);
+ comma = ',';
+ }
+ web_puts("];");
+}
+
+static void layer7_list(const char *path, int *first)
+{
+ DIR *dir;
+ struct dirent *de;
+ char *p;
+ char name[NAME_MAX];
+
+ if ((dir = opendir(path)) != NULL) {
+ while ((de = readdir(dir)) != NULL) {
+ strlcpy(name, de->d_name, sizeof(name));
+ if ((p = strstr(name, ".pat")) == NULL) continue;
+ *p = 0;
+ web_printf("%s'%s'", *first ? "" : ",", name);
+ *first = 0;
+ }
+ closedir(dir);
+ }
+}
+
+void asp_layer7(int argc, char **argv)
+{
+ int first = 1;
+ web_puts("\nlayer7 = [");
+ layer7_list("/etc/l7-extra", &first);
+ layer7_list("/etc/l7-protocols", &first);
+ web_puts("];\n");
+}
+
+void wo_expct(char *url)
+{
+ f_write_string("/proc/net/expire_early", "15", 0, 0);
+}
diff --git a/release/src/router/httpd/ddns.c b/release/src/router/httpd/ddns.c
new file mode 100644
index 00000000..2863cf72
--- /dev/null
+++ b/release/src/router/httpd/ddns.c
@@ -0,0 +1,90 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <time.h>
+#include <sys/stat.h>
+
+
+void asp_ddnsx(int argc, char **argv)
+{
+ char *p, *q;
+ int i;
+ char s[256];
+ char m[256];
+ char name[64];
+ time_t tt;
+ struct stat st;
+
+ switch (get_wan_proto()) {
+ case WP_PPTP:
+ p = "pptp_get_ip";
+ break;
+ case WP_L2TP:
+ p = "l2tp_get_ip";
+ break;
+ default:
+ p = "wan_ipaddr";
+ break;
+ }
+
+ web_printf(
+ "\nddnsx_ip = '%s';\n"
+ "ddnsx_msg = [",
+ nvram_safe_get(p));
+
+ for (i = 0; i < 2; ++i) {
+ web_puts(i ? "','" : "'");
+ sprintf(name, "/var/lib/mdu/ddnsx%d.msg", i);
+ f_read_string(name, m, sizeof(m)); // null term'd even on error
+ if (m[0] != 0) {
+ if ((stat(name, &st) == 0) && (st.st_mtime > Y2K)) {
+ strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z: ", localtime(&st.st_mtime));
+ web_puts(s);
+ }
+ web_putj(m);
+ }
+ }
+
+ web_puts("'];\nddnsx_last = [");
+
+ for (i = 0; i < 2; ++i) {
+ web_puts(i ? "','" : "'");
+ sprintf(name, "ddnsx%d", i);
+ if (!nvram_match(name, "")) {
+ sprintf(name, "ddnsx%d_cache", i);
+ if ((p = nvram_get(name)) == NULL) continue;
+ tt = strtoul(p, &q, 10);
+ if (*q++ != ',') continue;
+ if (tt > Y2K) {
+ strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z: ", localtime(&tt));
+ web_puts(s);
+ }
+ web_putj(q);
+ }
+ }
+ web_puts("'];\n");
+}
+
+void asp_ddnsx_ip(int argc, char **argv)
+{
+ const char *p;
+
+ switch (get_wan_proto()) {
+ case WP_PPTP:
+ p = "pptp_get_ip";
+ break;
+ case WP_L2TP:
+ p = "l2tp_get_ip";
+ break;
+ default:
+ p = "wan_ipaddr";
+ break;
+ }
+ web_puts(nvram_safe_get(p));
+}
diff --git a/release/src/router/httpd/devlist.c b/release/src/router/httpd/devlist.c
new file mode 100644
index 00000000..b72fd58b
--- /dev/null
+++ b/release/src/router/httpd/devlist.c
@@ -0,0 +1,229 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <wlutils.h>
+
+
+void asp_arplist(int argc, char **argv)
+{
+ FILE *f;
+ char s[512];
+ char ip[16];
+ char mac[18];
+ char dev[17];
+ char comma;
+ unsigned int flags;
+
+ /*
+ cat /proc/net/arp
+ IP address HW type Flags HW address Mask Device
+ 192.168.0.1 0x1 0x2 00:01:02:03:04:05 * vlan1
+ */
+
+ web_puts("\narplist = [");
+ comma = ' ';
+ if ((f = fopen("/proc/net/arp", "r")) != NULL) {
+ while (fgets(s, sizeof(s), f)) {
+ if (sscanf(s, "%15s %*s 0x%X %17s %*s %16s", ip, &flags, mac, dev) != 4) continue;
+ if ((strlen(mac) != 17) || (strcmp(mac, "00:00:00:00:00:00") == 0)) continue;
+ if (flags == 0) continue;
+// if ((nvram_match("wan_ifname", dev)) && (!nvram_match("wan_ipaddr", ip))) continue; // half
+ web_printf("%c['%s','%s','%s']", comma, ip, mac, dev);
+ comma = ',';
+ }
+ fclose(f);
+ }
+ web_puts("];\n");
+}
+
+// checkme: any easier way to do this? zzz
+static int get_wds_ifname(const struct ether_addr *ea, char *ifname)
+{
+ struct ifreq ifr;
+ int sd;
+ int i;
+ struct ether_addr e;
+
+ if ((sd = socket(PF_INET, SOCK_DGRAM, 0)) >= 0) {
+ // wds doesn't show up under SIOCGIFCONF; seems to start at 17 (?)
+ for (i = 1; i < 32; ++i) {
+ ifr.ifr_ifindex = i;
+ if ((ioctl(sd, SIOCGIFNAME, &ifr) == 0) &&
+ (strncmp(ifr.ifr_name, "wds", 3) == 0) &&
+ (wl_ioctl(ifr.ifr_name, WLC_WDS_GET_REMOTE_HWADDR, &e.octet, sizeof(e.octet)) == 0)) {
+ if (memcmp(ea->octet, e.octet, sizeof(e.octet)) == 0) {
+ close(sd);
+ strlcpy(ifname, ifr.ifr_name, 16);
+ return 1;
+ }
+ }
+ }
+ close(sd);
+ }
+ return 0;
+}
+
+void asp_devlist(int argc, char **argv)
+{
+ char *p;
+ FILE *f;
+ char buf[1024];
+ int i;
+ char comma;
+
+ // must be here for easier call via update.cgi. arg is ignored
+ asp_arplist(0, NULL);
+ asp_wlnoise(0, NULL);
+
+ //
+
+ p = js_string(nvram_safe_get("dhcpd_static"));
+ web_printf("dhcpd_static = '%s'.split('>');\n", p ? p : "");
+ free(p);
+
+ //
+
+#if 1
+ char *wlif;
+ scb_val_t rssi;
+ sta_info_t sti;
+ int cmd;
+ struct maclist *mlist;
+ int mlsize;
+ char ifname[16];
+
+ web_puts("wldev = [");
+ comma = ' ';
+ mlsize = sizeof(struct maclist) + (255 * sizeof(struct ether_addr));
+ if ((mlist = malloc(mlsize)) != NULL) {
+ wlif = nvram_safe_get("wl0_ifname");
+ cmd = WLC_GET_ASSOCLIST;
+ while (1) {
+ mlist->count = 255;
+ if (wl_ioctl(wlif, cmd, mlist, mlsize) == 0) {
+ for (i = 0; i < mlist->count; ++i) {
+ rssi.ea = mlist->ea[i];
+ rssi.val = 0;
+ if (wl_ioctl(wlif, WLC_GET_RSSI, &rssi, sizeof(rssi)) != 0) continue;
+
+ // sta_info0<mac>
+ memset(&sti, 0, sizeof(sti));
+ strcpy((char *)&sti, "sta_info");
+ memcpy((char *)&sti + 9, rssi.ea.octet, 6);
+ if (wl_ioctl(wlif, WLC_GET_VAR, &sti, sizeof(sti)) != 0) continue;
+
+ p = wlif;
+ if (sti.flags & WL_STA_WDS) {
+ if (cmd != WLC_GET_WDSLIST) continue;
+ if ((sti.flags & WL_WDS_LINKUP) == 0) continue;
+ if (get_wds_ifname(&rssi.ea, ifname)) p = ifname;
+ }
+
+ web_printf("%c['%s','%s',%d]",
+ comma,
+ p,
+ ether_etoa(rssi.ea.octet, buf),
+ rssi.val);
+ comma = ',';
+ }
+ }
+ if (cmd == WLC_GET_WDSLIST) break;
+ cmd = WLC_GET_WDSLIST;
+ }
+ free(mlist);
+ }
+#else
+ char *wlif;
+ scb_val_t rssi;
+ sta_info_t sti;
+ int j;
+ struct maclist *mlist;
+ int mlsize;
+ char ifname[16];
+
+ web_puts("wldev = [");
+ comma = ' ';
+ mlsize = sizeof(struct maclist) + (127 * sizeof(struct ether_addr));
+ if ((mlist = malloc(mlsize)) != NULL) {
+ for (j = 0; j < 2; ++j) {
+ wlif = nvram_safe_get("wl0_ifname");
+ strcpy((char *)mlist, j ? "autho_sta_list" : "authe_sta_list");
+ if (wl_ioctl(wlif, WLC_GET_VAR, mlist, mlsize) == 0) {
+ for (i = 0; i < mlist->count; ++i) {
+ rssi.ea = mlist->ea[i];
+ rssi.val = 0;
+ if (wl_ioctl(wlif, WLC_GET_RSSI, &rssi, sizeof(rssi)) != 0) continue;
+
+ // sta_info0<mac>
+ memset(&sti, 0, sizeof(sti));
+ strcpy((char *)&sti, "sta_info");
+ memcpy((char *)&sti + 9, rssi.ea.octet, 6);
+ if (wl_ioctl(wlif, WLC_GET_VAR, &sti, sizeof(sti)) != 0) continue;
+
+ p = wlif;
+ if (sti.flags & WL_STA_WDS) {
+ if ((sti.flags & WL_WDS_LINKUP) == 0) continue;
+ if (get_wds_ifname(&rssi.ea, ifname)) p = ifname;
+ }
+
+ web_printf("%c['%s','%s',%d]",
+ comma,
+ p,
+ ether_etoa(rssi.ea.octet, buf),
+ rssi.val);
+ comma = ',';
+ }
+ }
+ }
+ free(mlist);
+ }
+#endif
+
+ web_puts("];\n");
+
+ //
+
+ unsigned long expires;
+ char mac[32];
+ char ip[32];
+ char hostname[256];
+ char *host;
+
+ web_puts("dhcpd_lease = [");
+ if (nvram_match("lan_proto", "dhcp")) {
+ f_write("/var/tmp/dhcp/leases.!", NULL, 0, 0, 0666);
+
+ // dump the leases to a file
+ if (killall("dnsmasq", SIGUSR2) == 0) {
+ // helper in dnsmasq will remove this when it's done
+ f_wait_notexists("/var/tmp/dhcp/leases.!", 5);
+ }
+
+ if ((f = fopen("/var/tmp/dhcp/leases", "r")) != NULL) {
+ comma = ' ';
+ while (fgets(buf, sizeof(buf), f)) {
+ if (sscanf(buf, "%lu %17s %15s %255s", &expires, mac, ip, hostname) != 4) continue;
+ host = js_string((hostname[0] == '*') ? "" : hostname);
+ web_printf("%c['%s','%s','%s','%s']", comma,
+ (host ? host : ""), ip, mac, ((expires == 0) ? "non-expiring" : reltime(buf, expires)));
+ free(host);
+ comma = ',';
+ }
+ fclose(f);
+ }
+ unlink("/var/tmp/dhcp/leases");
+ }
+ web_puts("];");
+}
diff --git a/release/src/router/httpd/dhcp.c b/release/src/router/httpd/dhcp.c
new file mode 100644
index 00000000..aef5bcd3
--- /dev/null
+++ b/release/src/router/httpd/dhcp.c
@@ -0,0 +1,62 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <sys/sysinfo.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+
+void asp_dhcpc_time(int argc, char **argv)
+{
+ long exp;
+ struct sysinfo si;
+ long n;
+ int r;
+ char buf[32];
+
+ if (using_dhcpc()) {
+ exp = 0;
+ r = f_read_string("/var/lib/misc/dhcpc.expires", buf, sizeof(buf));
+ if (r > 0) {
+ n = atol(buf);
+ if (n > 0) {
+ sysinfo(&si);
+ exp = n - si.uptime;
+ }
+ }
+ web_puts(reltime(buf, exp));
+ }
+}
+
+void wo_dhcpc(char *url)
+{
+ char *p;
+
+ if ((p = webcgi_get("exec")) != NULL) {
+ if (strcmp(p, "release") == 0) eval("dhcpc-release");
+ else if (strcmp(p, "renew") == 0) eval("dhcpc-renew");
+ }
+ common_redirect();
+}
+
+
+// -----------------------------------------------------------------------------
+
+
+void wo_dhcpd(char *url)
+{
+ char *p;
+
+ if ((p = webcgi_get("remove")) != NULL) {
+ f_write_string("/var/tmp/dhcp/delete", p, FW_CREATE|FW_NEWLINE, 0666);
+ killall("dnsmasq", SIGUSR2);
+ f_wait_notexists("/var/tmp/dhcp/delete", 5);
+ }
+ web_puts("{}");
+}
diff --git a/release/src/router/httpd/ej.c b/release/src/router/httpd/ej.c
deleted file mode 100644
index d94aa601..00000000
--- a/release/src/router/httpd/ej.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Tiny Embedded JavaScript parser
- *
- * Copyright 2005, Broadcom Corporation
- * All Rights Reserved.
- *
- * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
- * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
- * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
- *
- * $Id: ej.c,v 1.9 2005/03/07 08:35:32 kanki Exp $
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "httpd.h"
-
-static char * get_arg(char *args, char **next);
-//static void call(char *func, FILE *stream);
-static void call(char *func, webs_t stream);
-
-/* Look for unquoted character within a string */
-static char *
-unqstrstr(char *haystack, char *needle)
-{
- char *cur;
- int q;
-
- for (cur = haystack, q = 0;
- cur < &haystack[strlen(haystack)] && !(!q && !strncmp(needle, cur, strlen(needle)));
- cur++) {
- if (*cur == '"')
- q ? q-- : q++;
- }
- return (cur < &haystack[strlen(haystack)]) ? cur : NULL;
-}
-
-static char *
-get_arg(char *args, char **next)
-{
- char *arg, *end;
-
- /* Parse out arg, ... */
- if (!(end = unqstrstr(args, ","))) {
- end = args + strlen(args);
- *next = NULL;
- } else
- *next = end + 1;
-
- /* Skip whitespace and quotation marks on either end of arg */
- for (arg = args; isspace((int)*arg) || *arg == '"'; arg++);
- for (*end-- = '\0'; isspace((int)*end) || *end == '"'; end--)
- *end = '\0';
-
- return arg;
-}
-
-static void
-//call(char *func, FILE *stream)
-call(char *func, webs_t stream) //jimmy, https, 8/4/2003
-{
- char *args, *end, *next;
- int argc;
- char * argv[16];
- struct ej_handler *handler;
-
- /* Parse out ( args ) */
- if (!(args = strchr(func, '(')))
- return;
- if (!(end = unqstrstr(func, ")")))
- return;
- *args++ = *end = '\0';
-
- /* Set up argv list */
- for (argc = 0; argc < 16 && args; argc++, args = next) {
- if (!(argv[argc] = get_arg(args, &next)))
- break;
- }
-
- /* Call handler */
- for (handler = &ej_handlers[0]; handler->pattern; handler++) {
- //if (strncmp(handler->pattern, func, strlen(handler->pattern)) == 0)
- if (strcmp(handler->pattern, func) == 0)
- handler->output(0, stream, argc, argv);
- }
-}
-
-void
-//do_ej(char *path, FILE *stream)
-do_ej(char *path, webs_t stream) // jimmy, https, 8/4/2003
-{
- FILE *fp;
- int c;
- char pattern[1000], *asp = NULL, *func = NULL, *end = NULL;
- int len = 0;
-
- if (!(fp = fopen(path, "r")))
- return;
-
- while ((c = getc(fp)) != EOF) {
-
- /* Add to pattern space */
- pattern[len++] = c;
- pattern[len] = '\0';
- if (len == (sizeof(pattern) - 1))
- goto release;
-
-
- /* Look for <% ... */
- if (!asp && !strncmp(pattern, "<%", len)) {
- if (len == 2)
- asp = pattern + 2;
- continue;
- }
-
- /* Look for ... %> */
- if (asp) {
- if (unqstrstr(asp, "%>")) {
- for (func = asp; func < &pattern[len]; func = end) {
- /* Skip initial whitespace */
- for (; isspace((int)*func); func++);
- if (!(end = unqstrstr(func, ";")))
- break;
- *end++ = '\0';
-
- /* Call function */
- call(func, stream);
- }
- asp = NULL;
- len = 0;
- }
- continue;
- }
-
- release:
- /* Release pattern space */
- //fputs(pattern, stream);
- if(wfputs(pattern, stream) == EOF) break; //jimmy, https, 8/4/2003
- len = 0;
- }
-
- fclose(fp);
-}
-
-int
-ejArgs(int argc, char **argv, char *fmt, ...)
-{
- va_list ap;
- int arg;
- char *c;
-
- if (!argv)
- return 0;
-
- va_start(ap, fmt);
- for (arg = 0, c = fmt; c && *c && arg < argc;) {
- if (*c++ != '%')
- continue;
- switch (*c) {
- case 'd':
- *(va_arg(ap, int *)) = atoi(argv[arg]);
- break;
- case 's':
- *(va_arg(ap, char **)) = argv[arg];
- break;
- }
- arg++;
- }
- va_end(ap);
-
- return arg;
-}
diff --git a/release/src/router/httpd/gencert.sh b/release/src/router/httpd/gencert.sh
index 52e64d96..8a1f837e 100755
--- a/release/src/router/httpd/gencert.sh
+++ b/release/src/router/httpd/gencert.sh
@@ -1,18 +1,29 @@
#!/bin/sh
+SECS=1167609600
-SECS=$1
+cd /etc
+
+NVCN=`nvram get https_crt_cn`
+if [ "$NVCN" == "" ]; then
+ NVCN=`nvram get lan_ipaddr`
+fi
+
+cp -L openssl.cnf openssl.config
+
+I=0
+for CN in $NVCN; do
+ echo "$I.commonName=CN" >> openssl.config
+ echo "$I.commonName_value=$CN" >> openssl.config
+ I=$(($I + 1))
+done
# create the key and certificate request
-openssl req -new -out /tmp/cert.csr -config /etc/openssl.cnf -keyout /tmp/privkey.pem -newkey rsa:512 -passout pass:password
+openssl req -new -out /tmp/cert.csr -config openssl.config -keyout /tmp/privkey.pem -newkey rsa:512 -passout pass:password
# remove the passphrase from the key
-openssl rsa -in /tmp/privkey.pem -out /tmp/key.pem -passin pass:password
+openssl rsa -in /tmp/privkey.pem -out key.pem -passin pass:password
# convert the certificate request into a signed certificate
-if test "$SECS" -eq "" ; then
- openssl x509 -in /tmp/cert.csr -out /tmp/cert.pem -req -signkey /tmp/key.pem -days 3650
-else
- openssl x509 -in /tmp/cert.csr -out /tmp/cert.pem -req -signkey /tmp/key.pem -days 3650 -setstartsecs $SECS
-fi
-# Show human-readable format
-openssl x509 -in /tmp/cert.pem -text -noout
-# Remove unused files
-rm -f /tmp/cert.csr /tmp/privkey.pem
+openssl x509 -in /tmp/cert.csr -out cert.pem -req -signkey key.pem -setstartsecs $SECS -days 3653 -set_serial $1
+
+# openssl x509 -in /etc/cert.pem -text -noout
+
+rm -f /tmp/cert.csr /tmp/privkey.pem openssl.config
diff --git a/release/src/router/httpd/httpd.c b/release/src/router/httpd/httpd.c
index 4a3288e3..034b7468 100644
--- a/release/src/router/httpd/httpd.c
+++ b/release/src/router/httpd/httpd.c
@@ -1,1202 +1,847 @@
+/*
+
+ micro_httpd/mini_httpd
+
+ Copyright © 1999,2000 by Jef Poskanzer <jef@acme.com>.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
/*
- *********************************************************
- * Copyright 2003, CyberTAN Inc. All Rights Reserved *
- *********************************************************
- This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
- the contents of this file may not be disclosed to third parties,
- copied or duplicated in any form without the prior written
- permission of CyberTAN Inc.
+ Copyright 2003, CyberTAN Inc. All Rights Reserved
+
+ This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc.
+ the contents of this file may not be disclosed to third parties,
+ copied or duplicated in any form without the prior written
+ permission of CyberTAN Inc.
- This software should be used as a reference only, and it not
- intended for production use!
+ This software should be used as a reference only, and it not
+ intended for production use!
+ THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
+ KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
+ SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
- THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
- KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
- SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
- FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE
*/
+/*
+
+ Modified for Tomato Firmware
+ Portions, Copyright (C) 2006-2009 Jonathan Zarate
-/* milli_httpd - pretty small HTTP server
-** A combination of
-** micro_httpd - really small HTTP server
-** and
-** mini_httpd - small HTTP server
-**
-** Copyright © 1999,2000 by Jef Poskanzer <jef@acme.com>.
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions
-** are met:
-** 1. Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** 2. Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in the
-** documentation and/or other materials provided with the distribution.
-**
-** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-** SUCH DAMAGE.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "tomato.h"
#include <errno.h>
#include <fcntl.h>
#include <time.h>
-#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <stdarg.h>
-#include <syslog.h>
-
-#include <cy_conf.h>
-#include "httpd.h"
-#include <bcmnvram.h>
-#include <code_pattern.h>
-#include <utils.h>
-#include <shutils.h>
-#if defined(HTTPS_SUPPORT)
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#endif
-#ifdef HSIAB_SUPPORT
-#include <hsiabutils.h>
-#define MAX_BUF_LEN 254
-#endif
-
+#include <sys/wait.h>
#include <error.h>
#include <sys/signal.h>
+#include <netinet/tcp.h>
+#include <sys/stat.h>
+
+#include <wlutils.h>
+
+
+#include "../mssl/mssl.h"
+int do_ssl;
-#define SERVER_NAME "httpd"
-//#define SERVER_PORT 80
-#define PROTOCOL "HTTP/1.0"
-#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
-#define TIMEOUT 1
-
-/* A multi-family sockaddr. */
-typedef union {
- struct sockaddr sa;
- struct sockaddr_in sa_in;
- } usockaddr;
-
-/* Globals. */
-#if defined(HTTPS_SUPPORT) // jimmy, https, 8/4/2003
- static SSL * ssl;
-#define DEFAULT_HTTPS_PORT 443
-#define CERT_FILE "/tmp/cert.pem"
-#define KEY_FILE "/tmp/key.pem"
-//#define DEBUG_CIPHER
-#endif
-#ifdef DEBUG_CIPHER
-char *set_ciphers = NULL;
-int get_ciphers = 0;
-#endif
-#define DEFAULT_HTTP_PORT 80
-extern int do_ssl;
-int server_port;
-char pid_file[80];
-#ifdef SAMBA_SUPPORT
-extern int smb_getlock;
-extern int httpd_fork;
-void smb_handler()
-{
- printf("============child exit=====waitting ...====\n");
- smb_getlock=0;
- wait(NULL);
- printf("wait finish \n");
-}
-#endif
-//static FILE *conn_fp;
-static webs_t conn_fp; // jimmy, https, 8/4/2003
-static char auth_userid[AUTH_MAX];
-static char auth_passwd[AUTH_MAX];
-static char auth_realm[AUTH_MAX];
-#ifdef MULTIPLE_LOGIN_SUPPORT
-static char auth_id_pw[AUTH_MAX];
-static char auth_mod[AUTH_MAX];
-#endif
-#ifdef GET_POST_SUPPORT
int post;
-#endif
-int auth_fail = 0;
-int httpd_level;
-
-char http_client_ip[20];
-extern char *get_mac_from_ip(char *ip);
-
-/* Forwards. */
-static int initialize_listen_socket( usockaddr* usaP );
-static int auth_check( char* dirname, char* authorization );
-static void send_authenticate( char* realm );
-static void send_error( int status, char* title, char* extra_header, char* text );
-static void send_headers( int status, char* title, char* extra_header, char* mime_type );
-static int b64_decode( const char* str, unsigned char* space, int size );
-static int match( const char* pattern, const char* string );
-static int match_one( const char* pattern, int patternlen, const char* string );
+int listenfd;
+int connfd = -1;
+FILE *connfp = NULL;
+struct sockaddr_in clientsai;
+int header_sent;
+char *user_agent;
+// int hidok = 0;
+
+const char mime_html[] = "text/html; charset=utf-8";
+const char mime_plain[] = "text/plain";
+const char mime_javascript[] = "text/javascript";
+const char mime_binary[] = "application/tomato-binary-file"; // instead of "application/octet-stream" to make browser just "save as" and prevent automatic detection weirdness -- zzz
+const char mime_octetstream[] = "application/octet-stream";
+
+static int match(const char* pattern, const char* string);
+static int match_one(const char* pattern, int patternlen, const char* string);
static void handle_request(void);
-static int
-initialize_listen_socket( usockaddr* usaP )
- {
- int listen_fd;
- int i;
-
- memset( usaP, 0, sizeof(usockaddr) );
- usaP->sa.sa_family = AF_INET;
- usaP->sa_in.sin_addr.s_addr = htonl( INADDR_ANY );
- usaP->sa_in.sin_port = htons( server_port );
-
- listen_fd = socket( usaP->sa.sa_family, SOCK_STREAM, 0 );
- if ( listen_fd < 0 )
- {
- perror( "socket" );
- return -1;
- }
- (void) fcntl( listen_fd, F_SETFD, 1 );
- i = 1;
- if ( setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, (char*) &i, sizeof(i) ) < 0 )
- {
- perror( "setsockopt" );
- return -1;
+
+// --------------------------------------------------------------------------------------------------------------------
+
+
+static const char *http_status_desc(int status)
+{
+ switch (status) {
+ case 200:
+ return "OK";
+ case 302:
+ return "Found";
+ case 400:
+ return "Invalid Request";
+ case 401:
+ return "Unauthorized";
+ case 404:
+ return "Not Found";
+ case 501:
+ return "Not Implemented";
}
- if ( bind( listen_fd, &usaP->sa, sizeof(struct sockaddr_in) ) < 0 )
- {
- perror( "bind" );
- return -1;
+ return "Unknown";
+}
+
+void send_header(int status, const char* header, const char* mime, int cache)
+{
+ time_t now;
+ char tms[128];
+
+ now = time(NULL);
+ if (now < Y2K) now += Y2K;
+ strftime(tms, sizeof(tms), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); // RFC 1123
+ web_printf("HTTP/1.0 %d %s\r\n"
+ "Date: %s\r\n",
+ status, http_status_desc(status),
+ tms);
+
+ if (mime) web_printf("Content-Type: %s\r\n", mime);
+ if (cache > 0) {
+ web_printf("Cache-Control: max-age=%d\r\n", cache * 60);
}
- if ( listen( listen_fd, 1024 ) < 0 )
- {
- perror( "listen" );
- return -1;
+ else {
+ web_puts("Cache-Control: no-cache, no-store, must-revalidate, private\r\n"
+ "Expires: Thu, 31 Dec 1970 00:00:00 GMT\r\n"
+ "Pragma: no-cache\r\n");
}
- return listen_fd;
- }
-
-
-static int
-auth_check( char* dirname, char* authorization )
- {
- char authinfo[500];
- char* authpass;
- int l;
-#ifdef MULTIPLE_LOGIN_SUPPORT
- int count;
- char word[1024], *next,*accounts;
- char delim[] = "<&nbsp;>";
-#endif
- /* Is this directory unprotected? */
- if ( !strlen(auth_passwd) )
- /* Yes, let the request go through. */
- return 1;
+ if (header) web_printf("%s\r\n", header);
+ web_puts("Connection: close\r\n\r\n");
- /* Basic authorization info? */
- if ( !authorization || strncmp( authorization, "Basic ", 6 ) != 0 ) {
- //send_authenticate( dirname );
- ct_syslog(LOG_INFO, httpd_level, "Authentication fail");
- return 0;
- }
-
- /* Decode it. */
- l = b64_decode( &(authorization[6]), authinfo, sizeof(authinfo) );
- authinfo[l] = '\0';
- /* Split into user and password. */
- authpass = strchr( authinfo, ':' );
- if ( authpass == (char*) 0 ) {
- /* No colon? Bogus auth info. */
- //send_authenticate( dirname );
- return 0;
- }
- *authpass++ = '\0';
-
- /* Is this the right user and password? */
-#ifdef DDM_SUPPORT
- #ifdef MULTIPLE_LOGIN_SUPPORT
- count =0;
- accounts = nvram_safe_get("http_login");
- split(word, accounts, next, delim) {
- int len = 0;
- char *name,*psw,*mod;
-
- memset(auth_passwd,0,sizeof(auth_passwd));
- memset(auth_mod,0,sizeof(auth_mod));
- memset(auth_userid,0,sizeof(auth_userid));
-
- if ((name=strstr(word, "$NAME:")) == NULL ||
- (psw=strstr(word, "$PSW:")) == NULL ||
- (mod=strstr(word, "$MOD:")) == NULL)
- continue;
-
- /* $NAME */
- if (sscanf(name, "$NAME:%3d:", &len) != 1)
- continue;
- strncpy(auth_userid, name + sizeof("$NAME:nnn:") - 1, len);
- name[len] = '\0';
-
- /* $PSW */
- if (sscanf(psw, "$PSW:%3d:", &len) != 1)
- continue;
- strncpy(auth_passwd, psw + sizeof("$PSW:nnn:") - 1, len);
- psw[len] = '\0';
-
- /* $MOD */
- if (sscanf(mod, "$MOD:%3d:", &len) != 1)
- continue;
- strncpy(auth_mod, mod + sizeof("$MOD:nnn:") - 1, len);
- mod[len] = '\0';
-
-// printf("accounts[%d]= name:%s, psw:%s, mod:%s system= id:%s, psw:%s\n", count, auth_userid, auth_passwd, auth_mod, authinfo, authpass);
- count++;
-
- if (strcmp( auth_userid, authinfo ) == 0 && strcmp( auth_passwd, authpass ) == 0 )
- {
- nvram_set("current_login_name",auth_userid);
+ header_sent = 1;
+}
+
+void send_error(int status, const char *header, const char *text)
+{
+ const char *s = http_status_desc(status);
+ send_header(status, header, mime_html, 0);
+ web_printf(
+ "<html>"
+ "<head><title>Error</title></head>"
+ "<body>"
+ "<h2>%d %s</h2> %s"
+ "</body></html>",
+ status, s, text ? text : s);
+}
+
+void redirect(const char *path)
+{
+ char s[512];
+
+ snprintf(s, sizeof(s), "Location: %s", path);
+ send_header(302, s, mime_html, 0);
+ web_puts(s);
+
+ _dprintf("Redirect: %s\n", path);
+}
+
+int skip_header(int *len)
+{
+ char buf[2048];
+
+ while (*len > 0) {
+ if (!web_getline(buf, MIN(*len, sizeof(buf)))) {
+ break;
+ }
+ *len -= strlen(buf);
+ if ((strcmp(buf, "\n") == 0) || (strcmp(buf, "\r\n") == 0)) {
return 1;
}
}
- #else
- if ( strcmp( auth_userid, authinfo ) == 0 && strcmp( auth_passwd, authpass ) == 0 )
- {
- return 1;
- }
- #endif
-#else
- if (strcmp( auth_passwd, authpass ) == 0 )
- return 1;
-#endif
- //send_authenticate( dirname );
- return 0;
- }
-
-
-static void
-send_authenticate( char* realm )
- {
- char header[10000];
-
- (void) snprintf(
- header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", realm );
- send_error( 401, "Unauthorized", header, "Authorization required." );
- }
-
-
-static void
-send_error( int status, char* title, char* extra_header, char* text )
- {
-
- // jimmy, https, 8/4/2003, fprintf -> wfprintf, fflush -> wfflush
- send_headers( status, title, extra_header, "text/html" );
- (void) wfprintf( conn_fp, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#cc9999\"><H4>%d %s</H4>\n", status, title, status, title );
- (void) wfprintf( conn_fp, "%s\n", text );
- (void) wfprintf( conn_fp, "</BODY></HTML>\n" );
- (void) wfflush( conn_fp );
- }
-
-static void
-send_headers( int status, char* title, char* extra_header, char* mime_type )
- {
- time_t now;
- char timebuf[100];
-
- // jimmy, https, 8/4/2003, fprintf -> wfprintf
- wfprintf( conn_fp, "%s %d %s\r\n", PROTOCOL, status, title );
- wfprintf( conn_fp, "Server: %s\r\n", SERVER_NAME );
- now = time( (time_t*) 0 );
- strftime( timebuf, sizeof(timebuf), RFC1123FMT, gmtime( &now ) );
- wfprintf( conn_fp, "Date: %s\r\n", timebuf );
- if ( extra_header != (char*) 0 && *extra_header)
- wfprintf( conn_fp, "%s\r\n", extra_header );
- if ( mime_type != (char*) 0 )
- wfprintf( conn_fp, "Content-Type: %s\r\n", mime_type );
- wfprintf( conn_fp, "Connection: close\r\n" );
- wfprintf( conn_fp, "\r\n" );
- }
-
-
-/* Base-64 decoding. This represents binary data as printable ASCII
-** characters. Three 8-bit binary bytes are turned into four 6-bit
-** values, like so:
-**
-** [11111111] [22222222] [33333333]
-**
-** [111111] [112222] [222233] [333333]
-**
-** Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
-*/
+ return 0;
+}
-static int b64_decode_table[256] = {
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */
- 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */
- 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */
- -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */
- 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */
- };
-
-/* Do base-64 decoding on a string. Ignore any non-base64 bytes.
-** Return the actual number of bytes generated. The decoded size will
-** be at most 3/4 the size of the encoded, and may be smaller if there
-** are padding characters (blanks, newlines).
-*/
-static int
-b64_decode( const char* str, unsigned char* space, int size )
- {
- const char* cp;
- int space_idx, phase;
- int d, prev_d=0;
- unsigned char c;
-
- space_idx = 0;
- phase = 0;
- for ( cp = str; *cp != '\0'; ++cp )
- {
- d = b64_decode_table[(int)*cp];
- if ( d != -1 )
- {
- switch ( phase )
- {
- case 0:
- ++phase;
- break;
- case 1:
- c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) );
- if ( space_idx < size )
- space[space_idx++] = c;
- ++phase;
- break;
- case 2:
- c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) );
- if ( space_idx < size )
- space[space_idx++] = c;
- ++phase;
- break;
- case 3:
- c = ( ( ( prev_d & 0x03 ) << 6 ) | d );
- if ( space_idx < size )
- space[space_idx++] = c;
- phase = 0;
- break;
- }
- prev_d = d;
- }
- }
- return space_idx;
- }
+// -----------------------------------------------------------------------------
-/* Simple shell-style filename matcher. Only does ? * and **, and multiple
-** patterns separated by |. Returns 1 or 0.
-*/
-int
-match( const char* pattern, const char* string )
- {
- const char* or;
-
- //Added by Daniel(2004-07-29) for DEBUG
- //cprintf("\nIn match(), pattern = %s, file = %s\n",pattern, string);
-
- for (;;)
- {
- or = strchr( pattern, '|' );
- if ( or == (char*) 0 )
- return match_one( pattern, strlen( pattern ), string );
- if ( match_one( pattern, or - pattern, string ) )
- return 1;
- pattern = or + 1;
- }
- }
-
-
-static int
-match_one( const char* pattern, int patternlen, const char* string )
- {
- const char* p;
-
- for ( p = pattern; p - pattern < patternlen; ++p, ++string )
- {
- if ( *p == '?' && *string != '\0' )
- continue;
- if ( *p == '*' )
- {
- int i, pl;
- ++p;
- if ( *p == '*' )
- {
- /* Double-wildcard matches anything. */
- ++p;
- i = strlen( string );
+static void eat_garbage(void)
+{
+ int i;
+ int flags;
+
+ // eat garbage \r\n (IE6, ...) or browser ends up with a tcp reset error message
+ if ((!do_ssl) && (post)) {
+ if (((flags = fcntl(connfd, F_GETFL)) != -1) && (fcntl(connfd, F_SETFL, flags | O_NONBLOCK) != -1)) {
+// if (fgetc(connfp) != EOF) fgetc(connfp);
+ for (i = 0; i < 1024; ++i) {
+ if (fgetc(connfp) == EOF) break;
+ }
+ fcntl(connfd, F_SETFL, flags);
}
- else
- /* Single-wildcard matches anything but slash. */
- i = strcspn( string, "/" );
- pl = patternlen - ( p - pattern );
- for ( ; i >= 0; --i )
- if ( match_one( p, pl, &(string[i]) ) )
- return 1;
- return 0;
- }
- if ( *p != *string )
- return 0;
}
- if ( *string == '\0' )
- return 1;
- return 0;
- }
+}
+// -----------------------------------------------------------------------------
-void
-//do_file(char *path, FILE *stream)
-do_file(char *path, webs_t stream) //jimmy, https, 8/4/2003
+static void send_authenticate(void)
{
- FILE *fp;
- int c;
-
- if (!(fp = fopen(path, "r")))
- return;
- while ((c = getc(fp)) != EOF)
- //fputc(c, stream);
- wfputc(c, stream); // jimmy, https, 8/4/2003
- fclose(fp);
+ char header[128];
+ const char *realm;
+
+ realm = nvram_get("router_name");
+ if ((realm == NULL) || (*realm == 0) || (strlen(realm) > 64)) realm = "unknown";
+
+ sprintf(header, "WWW-Authenticate: Basic realm=\"%s\"", realm);
+ send_error(401, header, NULL);
}
-#ifdef HSIAB_SUPPORT
-static char * // add by jimmy 2003-5-13
-get_aaa_url(int inout_mode, char *client_ip)
+typedef enum { AUTH_NONE, AUTH_OK, AUTH_BAD } auth_t;
+
+static auth_t auth_check(const char *authorization)
{
- static char line[MAX_BUF_LEN];
- char cmd[MAX_BUF_LEN];
-
- strcpy(line,"");
- if (inout_mode == 0)
- snprintf(cmd, sizeof(cmd),"GET aaa_login_url %s", client_ip);
- else
- snprintf(cmd, sizeof(cmd),"GET aaa_logout_url %s", client_ip);
-
- send_command(cmd, line);
-
- return line;
+ char buf[512];
+ const char *p;
+ char* pass;
+ int len;
+
+ if ((authorization != NULL) && (strncasecmp(authorization, "Basic ", 6) == 0)) {
+ if (base64_decoded_len(strlen(authorization + 6)) <= sizeof(buf)) {
+ len = base64_decode(authorization + 6, buf, strlen(authorization) - 6);
+ buf[len] = 0;
+ if ((pass = strchr(buf, ':')) != NULL) {
+ *pass++ = 0;
+ if ((strcmp(buf, "admin") == 0) || (strcmp(buf, "root") == 0)) {
+ p = nvram_get("http_passwd");
+ if (strcmp(pass, ((p == NULL) || (*p == 0)) ? "admin" : p) == 0) {
+ return AUTH_OK;
+ }
+ }
+ }
+ }
+ return AUTH_BAD;
+ }
+
+ return AUTH_NONE;
}
-char * // add by honor 2003-04-16, modify by jimmy 2003-05-13
-get_client_ip(int conn_fp)
+static void auth_fail(int clen)
{
- struct sockaddr_in sa;
- int len = sizeof(struct sockaddr_in);
- static char ip[20];
-
- getpeername(conn_fp, (struct sockaddr *)&sa, &len);
- strcpy(ip,inet_ntoa(sa.sin_addr));
- return(ip);
+ if (post) web_eat(clen);
+ eat_garbage();
+ send_authenticate();
}
-#endif
-static int
-check_connect_type(void)
+int check_wlaccess(void)
{
- struct wl_assoc_mac *wlmac = NULL;
- int count_wl = 0;
- int i;
+ char mac[32];
+ char ifname[32];
+ sta_info_t sti;
+
+ if (nvram_match("web_wl_filter", "1")) {
+ if (get_client_info(mac, ifname)) {
+ memset(&sti, 0, sizeof(sti));
+ strcpy((char *)&sti, "sta_info"); // sta_info0<mac>
+ ether_atoe(mac, (char *)&sti + 9);
+ if (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_VAR, &sti, sizeof(sti)) == 0) {
+ if (nvram_match("debug_logwlac", "1")) {
+ syslog(LOG_WARNING, "Wireless access from %s blocked.", mac);
+ }
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
- if(nvram_invmatch("web_wl_filter", "1"))
- return 0;
+// -----------------------------------------------------------------------------
- wlmac = get_wl_assoc_mac(&count_wl);
-
- for(i=0 ; i<count_wl ; i++) {
- if(!strcmp(wlmac[i].mac, nvram_safe_get("http_client_mac"))) {
- cprintf("Cann't accept wireless access\n");
- return -1;
+static int match_one(const char* pattern, int patternlen, const char* string)
+{
+ const char* p;
+
+ for (p = pattern; p - pattern < patternlen; ++p, ++string) {
+ if (*p == '?' && *string != '\0')
+ continue;
+ if (*p == '*') {
+ int i, pl;
+ ++p;
+ if (*p == '*') {
+ /* Double-wildcard matches anything. */
+ ++p;
+ i = strlen(string);
+ } else
+ /* Single-wildcard matches anything but slash. */
+ i = strcspn(string, "/");
+ pl = patternlen - (p - pattern);
+ for (; i >= 0; --i)
+ if (match_one(p, pl, &(string[i])))
+ return 1;
+ return 0;
}
+ if (*p != *string)
+ return 0;
}
-
+ if (*string == '\0')
+ return 1;
return 0;
}
-
-#ifdef GOOGLE_SUPPORT
-static void
-add_google_pass_mac(void)
+// Simple shell-style filename matcher. Only does ? * and **, and multiple
+// patterns separated by |. Returns 1 or 0.
+static int match(const char* pattern, const char* string)
{
- char *google_mac = nvram_safe_get("google_pass_mac");
- char *mac = nvram_safe_get("http_client_mac");
- char buf[1024];
+ const char* p;
- if(!strstr(google_mac, mac)) {
- snprintf(buf, sizeof(buf), "%s %s", google_mac, mac);
- nvram_set("google_pass_mac", buf);
-
- nvram_commit();
+ for (;;) {
+ p = strchr(pattern, '|');
+ if (p == NULL) return match_one(pattern, strlen(pattern), string);
+ if (match_one(pattern, p - pattern, string)) return 1;
+ pattern = p + 1;
}
-
- snprintf(buf, sizeof(buf), "iptables -I google -i %s -p tcp -m mac --mac-source %s -j ACCEPT",
- nvram_safe_get("lan_ifname"), nvram_safe_get("http_client_mac"));
- cprintf("buf[%s]\n", buf);
- system(buf);
- snprintf(buf, sizeof(buf), "iptables -t nat -I google -i %s -p tcp -m mac --mac-source %s -j ACCEPT",
- nvram_safe_get("lan_ifname"), nvram_safe_get("http_client_mac"));
- cprintf("buf[%s]\n", buf);
- system(buf);
}
-#endif
-static void
-handle_request(void)
+
+void do_file(char *path)
{
- char line[10000], *cur;
- char *method, *path, *protocol, *authorization, *boundary;
- char *cp;
- char *file;
-#ifdef MULTIPLE_LOGIN_SUPPORT
- char *file_ext;
-#endif
- int len;
- struct mime_handler *handler;
- int cl = 0, flags;
- int auth_no = 0;
- char *http_host = NULL;
- /* Initialize the request variables. */
- authorization = boundary = NULL;
- bzero( line, sizeof line );
-
- /* Parse the first line of the request. */
- if ( wfgets( line, sizeof(line), conn_fp ) == (char *)0 ) { //jimmy,https,8/4/2003
- send_error( 400, "Bad Request", (char*) 0, "No request found." );
- return;
- }
-
- /* To prevent http receive https packets, cause http crash (by honor 2003/09/02) */
- if ( strncasecmp(line, "GET", 3) && strncasecmp(line, "POST", 4)) {
- fprintf(stderr, "Bad Request!\n");
- return;
- }
-
- method = path = line;
- strsep(&path, " ");
- if (!path) { // Avoid http server crash, added by honor 2003-12-08
- send_error( 400, "Bad Request", (char*) 0, "Can't parse request." );
- return;
- }
- while (*path == ' ') path++;
- protocol = path;
- strsep(&protocol, " ");
- if (!protocol) { // Avoid http server crash, added by honor 2003-12-08
- send_error( 400, "Bad Request", (char*) 0, "Can't parse request." );
- return;
- }
- while (*protocol == ' ') protocol++;
- cp = protocol;
- strsep(&cp, " ");
- cur = protocol + strlen(protocol) + 1;
-
- /* Parse the rest of the request headers. */
- //while ( fgets( cur, line + sizeof(line) - cur, conn_fp ) != (char*) 0 )
- while ( wfgets( cur, line + sizeof(line) - cur, conn_fp ) != 0 ) //jimmy,https,8/4/2003
- {
-
- if ( strcmp( cur, "\n" ) == 0 || strcmp( cur, "\r\n" ) == 0 ){
- break;
- }
- else if ( strncasecmp( cur, "Authorization:", 14 ) == 0 )
- {
- cp = &cur[14];
- cp += strspn( cp, " \t" );
- authorization = cp;
- cur = cp + strlen(cp) + 1;
- }
- else if (strncasecmp( cur, "Content-Length:", 15 ) == 0) {
- cp = &cur[15];
- cp += strspn( cp, " \t" );
- cl = strtoul( cp, NULL, 0 );
+ FILE *f;
+ char buf[1024];
+ int nr;
+ if ((f = fopen(path, "r")) != NULL) {
+ while ((nr = fread(buf, 1, sizeof(buf), f)) > 0)
+ web_write(buf, nr);
+ fclose(f);
}
- else if ((cp = strstr( cur, "boundary=" ))) {
- boundary = &cp[9];
- for( cp = cp + 9; *cp && *cp != '\r' && *cp != '\n'; cp++ );
- *cp = '\0';
- cur = ++cp;
+}
+
+static void handle_request(void)
+{
+ char line[10000], *cur;
+ char *method, *path, *protocol, *authorization, *boundary;
+ char *cp;
+ char *file;
+ const struct mime_handler *handler;
+ int cl = 0;
+ auth_t auth;
+
+ user_agent = "";
+ header_sent = 0;
+ authorization = boundary = NULL;
+ bzero(line, sizeof(line));
+
+ // Parse the first line of the request.
+ if (!web_getline(line, sizeof(line))) {
+ send_error(400, NULL, NULL);
+ return;
}
- else if (strncasecmp(cur, "Host:" , 5 ) == 0) {
- cp = &cur[5 + 1];
- cp += strspn( cp, " \t" );
- http_host = cp;
- cur = cp + strlen(cp) + 1;
- chomp(http_host);
- }
+ _dprintf("%s\n", line);
+
+ method = path = line;
+ strsep(&path, " ");
+ if (!path) { // Avoid http server crash, added by honor 2003-12-08
+ send_error(400, NULL, NULL);
+ return;
}
-
-#ifdef HSIAB_SUPPORT
- if(strstr(path,"/logout/")){
- char *logout_url;
- char buf[MAX_BUF_LEN];
- char value[MAX_BUF_LEN];
-
- snprintf(value, sizeof(value), "LOG aaa_redirect logout %s %s", nvram_safe_get("http_client_ip"), nvram_safe_get("http_client_mac"));
- send_command(value, NULL);
-
- logout_url = get_aaa_url(1, nvram_safe_get("http_client_ip"));
- if(!strcmp(logout_url, "fail")){
- printf("Get logout URL fail!\n");
+ while (*path == ' ') path++;
+
+ if ((strcasecmp(method, "GET") != 0) && (strcasecmp(method, "POST") != 0)) {
+ send_error(501, NULL, NULL);
return;
}
- fprintf(stderr, "User will redirect to this URL...[%s]\n", logout_url);
- sprintf(buf,"Location: %s",logout_url);
- (void) send_headers(302,"Redirect",(char *)buf,"text/plain");
- return;
-
- }
-#endif
- if ( strcasecmp( method, "get" ) != 0 && strcasecmp(method, "post") != 0 ) {
- send_error( 501, "Not Implemented", (char*) 0, "That method is not implemented." );
- return;
- }
- if ( path[0] != '/' ) {
- send_error( 400, "Bad Request", (char*) 0, "Bad filename." );
- return;
- }
- file = &(path[1]);
- len = strlen( file );
- //Added by Daniel(2004-07-29) for DEBUG in EZC
- //cprintf("\nIn handle_request() file: [%s] \n", file);
- if ( file[0] == '/' || strcmp( file, ".." ) == 0 || strncmp( file, "../", 3 ) == 0 || strstr( file, "/../" ) != (char*) 0 || strcmp( &(file[len-3]), "/.." ) == 0 ) {
- send_error( 400, "Bad Request", (char*) 0, "Illegal filename." );
- return;
- }
- if ( strcmp( &(file[len-1]), "/" ) == 0 && len > 0) //Amin 931231 deny request "http://ip/*/" return index.asp
- {
- send_error( 400, "Bad Request", (char*) 0, "Illegal filename." );
- return;
- }
-
-#ifdef MULTIPLE_LOGIN_SUPPORT
- if ( file[0] == '\0' || file[len-1] == '/' )
- {
- file = "index.asp";
- }
-#else
- if ( file[0] == '\0' || file[len-1] == '/' )
- {
- #ifdef MUST_CHANGE_PWD_SUPPORT
- if(!nvram_match("is_not_first_access","1"))
- file = "First_Management.asp";
- else
- #endif
- file = "index.asp";
- }
-#endif
-#ifdef GOOGLE_SUPPORT
- if (http_host &&
- strncasecmp( http_host, nvram_safe_get("lan_ipaddr"), strlen(nvram_safe_get("lan_ipaddr"))) &&
- strncasecmp( http_host, nvram_safe_get("wan_ipaddr"), strlen(nvram_safe_get("wan_ipaddr")))) {
- /* Redirect packet for first time */
- file = "google_redirect1.asp";
- auth_no = 1;
+ protocol = path;
+ strsep(&protocol, " ");
+ if (!protocol) { // Avoid http server crash, added by honor 2003-12-08
+ send_error(400, NULL, NULL);
+ return;
}
- else if (http_host &&
- !strncasecmp( http_host, nvram_safe_get("lan_ipaddr"), strlen(nvram_safe_get("lan_ipaddr"))) &&
- strstr(path, "accept_terms=I+Accept")) {
- /* Redirect packet for accepting terms */
- file = "google_redirect2.asp";
- auth_no = 1;
- add_google_pass_mac();
+ while (*protocol == ' ') protocol++;
+
+ if (path[0] != '/') {
+ send_error(400, NULL, NULL);
+ return;
}
-#endif
+ file = path + 1;
- for (handler = &mime_handlers[0]; handler->pattern; handler++) {
- if (match(handler->pattern, file)) {
- if (!auth_no && handler->auth) {
-#ifdef MULTIPLE_LOGIN_SUPPORT
- handler->auth(auth_id_pw, auth_passwd, auth_realm);
-#else
- handler->auth(auth_userid, auth_passwd, auth_realm); //r
-#endif
- auth_fail = 0;
- if (!auth_check(auth_realm, authorization)) {
- send_authenticate(auth_realm);
- return;
- //auth_fail = 1;
- }
-
- }
-#ifdef MULTIPLE_LOGIN_SUPPORT
- file_ext = strstr(file , ".");
-// printf("The request file name is : [%s], extern name is : [%s]\n",file,file_ext);
- if(!strcmp(file_ext,".asp") && strcmp(file, "Status_Lan2.asp") && strcmp(file, "Status_Wireless2.asp") && strcmp(file, "Status_Router2.asp") && strcmp(file, "DHCPTable2.asp") && strcmp(file, "Management_account.asp"))
- {
- if(strcmp(auth_mod, "admin"))
- {
- if(!strcmp(file, "Management.asp"))
- auth_fail = 1;
- else
- {
-// printf("change web url to Status_Router page\n");
- file = "Status_Router2.asp";
- }
- }
-// else
-// printf("Not change web url to Status_Router page\n");
- }
-#endif
-#ifdef GET_POST_SUPPORT
- post=0;
- if (strcasecmp(method, "post") == 0 ) {
- post=1;
- }
-#else
- if (strcasecmp(method, "post") == 0 && !handler->input) {
- send_error(501, "Not Implemented", NULL, "That method is not implemented.");
- return;
- }
+#if 0
+ const char *hid;
+ int n;
+
+ hid = nvram_safe_get("http_id");
+ n = strlen(hid);
+ cprintf("file=%s hid=%s n=%d +n=%s\n", file, hid, n, path + n + 1);
+ if ((strncmp(file, hid, n) == 0) && (path[n + 1] == '/')) {
+ path += n + 1;
+ file = path + 1;
+ hidok = 1;
+
+ cprintf("OK path=%s file=%s\n", path, file);
+ }
#endif
- if (handler->input) {
- //cprintf("\nIn Handle Request(INPUT)!!!\n");
- handler->input(file, conn_fp, cl, boundary);
-#if defined(linux)
- if ((flags = fcntl(fileno(conn_fp), F_GETFL)) != -1 &&
- fcntl(fileno(conn_fp), F_SETFL, flags | O_NONBLOCK) != -1) {
- /* Read up to two more characters */
- if (fgetc(conn_fp) != EOF)
- (void) fgetc(conn_fp);
- fcntl(fileno(conn_fp), F_SETFL, flags);
- }
-#endif
- }
-
- if(check_connect_type() <0 ){
- send_error(401, "Bad Request", (char*) 0, "Cann't use wireless interface to access web.");
- return;
- }
-
- if(auth_fail == 1){
- send_authenticate(auth_realm);
- return;
- }
- else
- send_headers( 200, "Ok", handler->extra_header, handler->mime_type );
-
- if (handler->output)
- {
- //cprintf("\nIn Handle Request(OUTPUT)!!!\n");
- handler->output(file, conn_fp);
- }
- break;
- }
- }
-
- if (!handler->pattern)
- send_error( 404, "Not Found", (char*) 0, "File not found." );
-}
-void // add by honor 2003-04-16
-get_client_ip_mac(int conn_fp)
-{
- struct sockaddr_in sa;
- int len = sizeof(struct sockaddr_in);
- char *m;
-
- getpeername(conn_fp, (struct sockaddr *)&sa, &len);
- nvram_safe_set("http_client_ip", inet_ntoa(sa.sin_addr));
- m = get_mac_from_ip(inet_ntoa(sa.sin_addr));
- nvram_safe_set("http_client_mac", m);
-}
+ if ((cp = strchr(file, '?')) != NULL) {
+ *cp = 0;
+ webcgi_init(cp + 1);
+ }
-static void
-handle_server_sig_int(int sig)
-{
- ct_syslog(LOG_INFO, httpd_level, "httpd server %sshutdown", do_ssl ? "(ssl support) " : "");
- exit(0);
-}
+ if ((file[0] == '/') || (strncmp(file, "..", 2) == 0) || (strstr(file, "/../") != NULL) ||
+ (strcmp(file + (strlen(file) - 3), "/..") == 0)) {
+ send_error(400, NULL, NULL);
+ return;
+ }
-void settimeouts(int sock, int secs)
-{
- struct timeval tv;
+ if ((file[0] == 0) || (strcmp(file, "index.asp") == 0)) {
+ file = "status-overview.asp";
+ }
+ else if ((strcmp(file, "ext/") == 0) || (strcmp(file, "ext") == 0)) {
+ file = "ext/index.asp";
+ }
- tv.tv_sec = secs;
- tv.tv_usec = 0;
- if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
- perror("setsockopt(SO_SNDTIMEO)");
- if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
- perror("setsockopt(SO_RCVTIMEO)");
-}
+ cp = protocol;
+ strsep(&cp, " ");
+ cur = protocol + strlen(protocol) + 1;
-int main(int argc, char **argv)
-{
- usockaddr usa;
- int listen_fd;
- int conn_fd;
- socklen_t sz = sizeof(usa);
- int c;
- int timeout = TIMEOUT;
- int n = 0;
-#if defined(HTTPS_SUPPORT) //jimmy, https, 8/4/2003
- BIO *sbio;
- SSL_CTX *ctx = NULL;
- int r;
- BIO *ssl_bio;
-#endif
- strcpy(pid_file, "/var/run/httpd.pid");
- server_port = DEFAULT_HTTP_PORT;
-
- while ((c = getopt(argc, argv, "Sp:t:s:gh")) != -1)
- switch (c) {
-#if defined(HTTPS_SUPPORT) //honor, https, 8/14/2003
- case 'S':
- do_ssl = 1;
- server_port = DEFAULT_HTTPS_PORT;
- strcpy(pid_file, "/var/run/httpsd.pid");
- break;
-#endif
- case 'p':
- server_port = atoi(optarg);
- break;
- case 't':
- timeout = atoi(optarg);
- break;
-#ifdef DEBUG_CIPHER
- case 's':
- set_ciphers = optarg;
- break;
- case 'g':
- get_ciphers = 1;
- break;
-#endif
- case 'h':
- fprintf(stderr, "Usage: %s [-S] [-p port]\n"
- " -S : Support https (port 443)\n"
- " -p port : Which port to listen?\n"
- " -t secs : How many seconds to wait before timing out?\n"
- " -s ciphers: set cipher lists\n"
- " -g: get cipher lists\n"
- , argv[0]);
- exit(0);
- break;
- default:
- break;
+ while (web_getline(cur, line + sizeof(line) - cur)) {
+ if ((strcmp(cur, "\n") == 0) || (strcmp(cur, "\r\n") == 0)) {
+ break;
}
-
-
- httpd_level = ct_openlog("httpd", LOG_PID | LOG_NDELAY, LOG_DAEMON, "LOG_HTTPD");
-
- ct_syslog(LOG_INFO, httpd_level, "httpd server %sstarted at port %d\n", do_ssl ? "(ssl support) " : "", server_port);
-
- /* Ignore broken pipes */
- signal(SIGPIPE, SIG_IGN);
-#ifdef SAMBA_SUPPORT
- /* handle child exit */
- signal(SIGCHLD, smb_handler);
-#endif
- signal(SIGTERM, handle_server_sig_int); // kill
-
-
-#if defined(HTTPS_SUPPORT) //jimmy, https, 8/4/2003
- /* Build our SSL context */
- if(do_ssl){
- SSLeay_add_ssl_algorithms();
- SSL_load_error_strings();
- ctx = SSL_CTX_new( SSLv23_server_method() );
- if ( SSL_CTX_use_certificate_file( ctx, CERT_FILE, SSL_FILETYPE_PEM ) == 0 ) {
- cprintf("Cann't read %s\n", CERT_FILE);
- ERR_print_errors_fp( stderr );
- exit( 1 );
+ if (strncasecmp(cur, "Authorization:", 14) == 0) {
+ cp = &cur[14];
+ cp += strspn(cp, " \t");
+ authorization = cp;
+ cur = cp + strlen(cp) + 1;
}
- if(SSL_CTX_use_PrivateKey_file( ctx, KEY_FILE, SSL_FILETYPE_PEM ) == 0 ) {
- cprintf("Cann't read %s\n", KEY_FILE);
- ERR_print_errors_fp( stderr );
- exit( 1 );
-
+ else if (strncasecmp(cur, "Content-Length:", 15) == 0) {
+ cp = &cur[15];
+ cp += strspn(cp, " \t");
+ cl = strtoul(cp, NULL, 0);
+ if ((cl < 0) || (cl >= INT_MAX)) {
+ send_error(400, NULL, NULL);
+ return;
+ }
}
- if(SSL_CTX_check_private_key( ctx ) == 0 ) {
- cprintf("Check private key fail\n");
- ERR_print_errors_fp( stderr );
- exit( 1 );
+ else if ((strncasecmp(cur, "Content-Type:", 13) == 0) && ((cp = strstr(cur, "boundary=")))) {
+ boundary = &cp[9];
+ for (cp = cp + 9; *cp && *cp != '\r' && *cp != '\n'; cp++);
+ *cp = '\0';
+ cur = ++cp;
}
- }
-#endif
- /* Initialize listen socket */
-retry:
- if ((listen_fd = initialize_listen_socket(&usa)) < 0) {
- ct_syslog(LOG_ERR, httpd_level, "Cann't bind to any address");
- close(listen_fd);
-
- sleep(2);
- if(n++ <= 5) {
- cprintf("Something error occur, retry %d\n", n);
- goto retry;
+ else if (strncasecmp(cur, "User-Agent:", 11) == 0) {
+ user_agent = cur + 11;
+ user_agent += strspn(user_agent, " \t");
+ cur = user_agent + strlen(user_agent);
+ *cur++ = 0;
}
-
- exit(errno);
- }
-
-#if !defined(DEBUG)
- {
- FILE *pid_fp;
- /* Daemonize and log PID */
- if (daemon(1, 1) == -1) {
- perror("daemon");
- exit(errno);
}
- if (!(pid_fp = fopen(pid_file, "w"))) {
- perror(pid_file);
- return errno;
- }
- fprintf(pid_fp, "%d", getpid());
- fclose(pid_fp);
+
+ post = (strcasecmp(method, "post") == 0);
+
+ auth = auth_check(authorization);
+
+#if 0
+ cprintf("UserAgent: %s\n", user_agent);
+ switch (auth) {
+ case AUTH_NONE:
+ cprintf("AUTH_NONE\n");
+ break;
+ case AUTH_OK:
+ cprintf("AUTH_OK\n");
+ break;
+ case AUTH_BAD:
+ cprintf("AUTH_BAD\n");
+ break;
+ default:
+ cprintf("AUTH_?\n");
+ break;
}
#endif
- /* Loop forever handling requests */
- for (;;) {
- if ((conn_fd = accept(listen_fd, &usa.sa, &sz)) < 0) {
- perror("accept");
- return errno;
- }
+ /*
+
+ Chrome 1.0.154:
+ - User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19
+ - It *always* sends an 'AUTH_NONE request' first. This results in a
+ send_authenticate, then finally sends an 'AUTH_OK request'.
+ - It does not clear the authentication even if AUTH_NONE request succeeds.
+ - If user doesn't enter anything (blank) for credential, it sends the
+ previous credential.
+
+ */
- /* Make sure we don't linger a long time if the other end disappears */
- settimeouts(conn_fd, timeout);
+ if (strcmp(file, "logout") == 0) { // special case
+ wi_generic(file, cl, boundary);
+ eat_garbage();
- if(check_action() == ACT_TFTP_UPGRADE || // We don't want user to use web during tftp upgrade.
- check_action() == ACT_SW_RESTORE ||
- check_action() == ACT_HW_RESTORE){
- fprintf(stderr, "http(s)d: nothing to do...\n");
- return -1;
+ if (strstr(user_agent, "Chrome/") != NULL) {
+ if (auth != AUTH_BAD) {
+ send_authenticate();
+ return;
+ }
}
-
-#if defined(HTTPS_SUPPORT) //jimmy, https, 8/4/2003
- if(do_ssl){
- if(check_action() == ACT_WEB_UPGRADE){ // We don't want user to use web (https) during web (http) upgrade.
- fprintf(stderr, "httpsd: nothing to do...\n");
- return -1;
+ else {
+ if (auth == AUTH_OK) {
+ send_authenticate();
+ return;
+ }
}
+ send_error(404, NULL, "Goodbye");
+ return;
+ }
- sbio=BIO_new_socket(conn_fd,BIO_NOCLOSE);
- ssl=SSL_new(ctx);
-
-#ifdef DEBUG_CIPHER
- check_cipher();
-#endif
-
- SSL_set_bio(ssl,sbio,sbio);
+ if (auth == AUTH_BAD) {
+ auth_fail(cl);
+ return;
+ }
- if((r=SSL_accept(ssl)<=0)){
- //berr_exit("SSL accept error");
- ct_syslog(LOG_ERR, httpd_level, "SSL accept error");
- close(conn_fd);
- continue;
+ for (handler = &mime_handlers[0]; handler->pattern; handler++) {
+ if (match(handler->pattern, file)) {
+ if ((handler->auth) && (auth != AUTH_OK)) {
+ auth_fail(cl);
+ return;
+ }
+
+ if (handler->input) handler->input(file, cl, boundary);
+ eat_garbage();
+ if (handler->mime_type != NULL) send_header(200, NULL, handler->mime_type, handler->cache);
+ if (handler->output) handler->output(file);
+ return;
}
+ }
- conn_fp=(webs_t)BIO_new(BIO_f_buffer());
- ssl_bio=BIO_new(BIO_f_ssl());
- BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE);
- BIO_push((BIO *)conn_fp,ssl_bio);
- }else
-#endif
- {
- if(check_action() == ACT_WEBS_UPGRADE){ // We don't want user to use web (http) during web (https) upgrade.
- fprintf(stderr, "httpd: nothing to do...\n");
- return -1;
- }
-
- if (!(conn_fp = fdopen(conn_fd, "r+"))) {
- perror("fdopen");
- return errno;
- }
- }
- get_client_ip_mac(conn_fd);
-
- handle_request();
-#ifdef SAMBA_SUPPORT
- if (httpd_fork==1) {
- httpd_fork=0;
- close(conn_fd);
- continue;
- }
-#endif
-
- wfflush(conn_fp); // jimmy, https, 8/4/2003
- wfclose(conn_fp); // jimmy, https, 8/4/2003
- close(conn_fd);
+ if (auth != AUTH_OK) {
+ auth_fail(cl);
+ return;
}
- shutdown(listen_fd, 2);
- close(listen_fd);
+/*
+ if ((!post) && (strchr(file, '.') == NULL)) {
+ cl = strlen(file);
+ if ((cl > 1) && (cl < 64)) {
+ char alt[128];
- return 0;
+ path = alt + 1;
+ strcpy(path, file);
+
+ cp = path + cl - 1;
+ if (*cp == '/') *cp = 0;
+
+ if ((cp = strrchr(path, '/')) != NULL) *cp = '-';
+
+ strcat(path, ".asp");
+ if (f_exists(path)) {
+ alt[0] = '/';
+ redirect(alt);
+ return;
+ }
+ }
+ }
+*/
+
+ send_error(404, NULL, NULL);
}
-char *
-wfgets(char *buf, int len, FILE *fp)
+#ifdef TCONFIG_HTTPS
+static void save_cert(void)
{
-#ifdef HTTPS_SUPPORT
- if(do_ssl)
- return (char *)BIO_gets((BIO *)fp, buf, len);
- else
-#endif
- return fgets(buf, len, fp);
+ if (eval("tar", "-C", "/", "-czf", "/tmp/cert.tgz", "etc/cert.pem", "etc/key.pem") == 0) {
+ if (nvram_set_file("https_crt_file", "/tmp/cert.tgz", 8192)) {
+ nvram_commit_x();
+ }
+ }
+ unlink("/tmp/cert.tgz");
}
-int
-wfputc(char c, FILE *fp)
+static void erase_cert(void)
{
-#ifdef HTTPS_SUPPORT
- if(do_ssl)
- return BIO_printf((BIO *)fp, "%c", c);
- else
-#endif
- return fputc(c, fp);
+ unlink("/etc/cert.pem");
+ unlink("/etc/key.pem");
+ nvram_unset("https_crt_file");
+ nvram_unset("https_crt_gen");
}
-int
-wfputs(char *buf, FILE *fp)
+static void start_ssl(void)
{
-#ifdef HTTPS_SUPPORT
- if(do_ssl)
- return BIO_puts((BIO *)fp, buf);
- else
-#endif
- return fputs(buf, fp);
+ int ok;
+ int save;
+ int retry;
+ unsigned long long sn;
+ char t[32];
+
+ if (nvram_match("https_crt_gen", "1")) {
+ erase_cert();
+ }
+
+ retry = 1;
+ while (1) {
+ save = nvram_match("https_crt_save", "1");
+
+ if ((!f_exists("/etc/cert.pem")) || (!f_exists("/etc/key.pem"))) {
+ ok = 0;
+ if (save) {
+ if (nvram_get_file("https_crt_file", "/tmp/cert.tgz", 8192)) {
+ if (eval("tar", "-xzf", "/tmp/cert.tgz", "-C", "/", "etc/cert.pem", "etc/key.pem") == 0)
+ ok = 1;
+ unlink("/tmp/cert.tgz");
+ }
+ }
+ if (!ok) {
+ erase_cert();
+ syslog(LOG_INFO, "Generating SSL certificate...");
+
+ // browsers seems to like this when the ip address moves... -- zzz
+ f_read("/dev/urandom", &sn, sizeof(sn));
+
+ sprintf(t, "%llu", sn & 0x7FFFFFFFFFFFFFFFUL);
+ eval("gencert.sh", t);
+ }
+ }
+
+ if ((save) && (*nvram_safe_get("https_crt_file")) == 0) {
+ save_cert();
+ }
+
+ if (ssl_init("/etc/cert.pem", "/etc/key.pem")) return;
+
+ erase_cert();
+
+ syslog(retry ? LOG_WARNING : LOG_ERR, "Unable to start SSL");
+ if (!retry) exit(1);
+ retry = 0;
+ }
}
+#endif
-int
-wfprintf(FILE *fp, char *fmt,...)
+static void init_id(void)
{
- va_list args;
- char buf[1024];
- int ret;
-
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf), fmt, args);
-#ifdef HTTPS_SUPPORT
- if(do_ssl)
- ret = BIO_printf((BIO *)fp, "%s", buf);
- else
-#endif
- ret = fprintf(fp, "%s", buf);
- va_end(args);
- return ret;
+ char s[128];
+ unsigned long long n;
+
+ if (strncmp(nvram_safe_get("http_id"), "TID", 3) != 0) {
+ f_read("/dev/urandom", &n, sizeof(n));
+ sprintf(s, "TID%llx", n);
+ nvram_set("http_id", s);
+ }
+
+ nvram_unset("http_id_warn");
}
-size_t
-wfwrite(char *buf, int size, int n, FILE *fp)
+void check_id(const char *url)
{
-#ifdef HTTPS_SUPPORT
- if(do_ssl)
- return BIO_write((BIO *)fp, buf , n * size);
- else
+ if (!nvram_match("http_id", webcgi_safeget("_http_id", ""))) {
+#if 0
+ const char *hid = nvram_safe_get("http_id");
+ if (url) {
+ const char *a;
+ int n;
+
+ // http://xxx/yyy/TID/zzz
+ if (((a = strrchr(url, '/')) != NULL) && (a != url)) {
+ n = strlen(hid);
+ a -= n;
+ if ((a > url) && (*(a - 1) == '/')) {
+ if (strncmp(a, hid, n) == 0) return;
+ }
+ }
+ }
+
#endif
- return fwrite(buf,size,n,fp);
+
+ char s[48];
+ char *i;
+ char *u;
+ const char *a;
+
+ a = inet_ntoa(clientsai.sin_addr);
+ sprintf(s, "%s,%ld", a, time(NULL) & 0xFFC0);
+ if (!nvram_match("http_id_warn", s)) {
+ nvram_set("http_id_warn", s);
+
+ strlcpy(s, webcgi_safeget("_http_id", ""), sizeof(s));
+ i = js_string(s); // quicky scrub
+
+ strlcpy(s, url, sizeof(s));
+ u = js_string(s);
+
+ if ((i != NULL) && (u != NULL)) {
+ syslog(LOG_WARNING, "Invalid ID '%s' from %s for /%s", i, a, u);
+ }
+
+ // free(u);
+ // free(i);
+ }
+
+ exit(1);
+ }
}
-size_t
-wfread(char *buf, int size, int n, FILE *fp)
+int main(int argc, char **argv)
{
-#ifdef HTTPS_SUPPORT
- if(do_ssl)
- return BIO_read((BIO *)fp, buf , n * size);
- else
+ int c;
+ int debug = 0;
+ int server_port = 0;
+
+ while ((c = getopt(argc, argv, "hdp:s")) != -1) {
+ switch (c) {
+ case 'h':
+ printf(
+ "Usage: %s [options]\n"
+ " -d Debug mode / do not demonize\n"
+ " -p <port> Port to listen on\n"
+#ifdef TCONFIG_HTTPS
+ " -s Use HTTPS\n"
+#endif
+ , argv[0]);
+ return 1;
+ case 'd':
+ debug = 1;
+ break;
+ case 'p':
+ server_port = atoi(optarg);
+ break;
+#ifdef TCONFIG_HTTPS
+ case 's':
+ do_ssl = 1;
+ break;
#endif
- return fread(buf,size,n,fp);
-}
+ }
+ }
-int
-wfflush(FILE *fp)
-{
-#ifdef HTTPS_SUPPORT
- if(do_ssl){
- BIO_flush((BIO *)fp);
- return 1;
+ if (server_port == 0) {
+#ifdef TCONFIG_HTTPS
+ if (do_ssl) {
+ server_port = nvram_get_int("https_lanport");
+ if (server_port <= 0) server_port = 443;
+ }
+ else {
+ server_port = nvram_get_int("http_lanport");
+ if (server_port <= 0) server_port = 80;
+ }
+#else
+ server_port = nvram_get_int("http_lanport");
+ if (server_port <= 0) server_port = 80;
+#endif
+ }
+
+ openlog("httpd", LOG_PID, LOG_DAEMON);
+
+ if (!debug) {
+ if (daemon(1, 1) == -1) {
+ syslog(LOG_ERR, "daemon: %m");
+ return 0;
+ }
+
+
+ char s[16];
+ sprintf(s, "%d", getpid());
+ f_write_string(do_ssl ? "/var/run/httpsd.pid" : "/var/run/httpd.pid", s, 0, 0644);
}
- else
+ else {
+ printf("DEBUG mode, not daemonizing\n");
+ }
+
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+
+#ifdef TCONFIG_HTTPS
+ if (do_ssl) start_ssl();
#endif
- return fflush(fp);
-}
-int
-wfclose(FILE *fp)
-{
-#ifdef HTTPS_SUPPORT
- if(do_ssl){
- BIO_free_all((BIO *)fp);
+ struct timeval tv;
+ int n;
+
+ if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "create listening socket: %m");
+ return 1;
+ }
+ fcntl(listenfd, F_SETFD, FD_CLOEXEC);
+ n = 1;
+ setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof(n));
+
+ struct sockaddr_in sai;
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(server_port);
+ sai.sin_addr.s_addr = INADDR_ANY;
+ if (bind(listenfd, (struct sockaddr *)&sai, sizeof(sai)) < 0) {
+ syslog(LOG_ERR, "bind: %m");
return 1;
}
- else
-#endif
- return fclose(fp);
-}
-#ifdef DEBUG_CIPHER
-void check_cipher(void)
-{
- STACK_OF(SSL_CIPHER) *sk;
- char buf[512];
- BIO *STDout = NULL;
- int i;
- static BIO *bio_stdout=NULL;
- X509 *peer;
- static BIO *bio_s_out=NULL;
- SSL_CIPHER *ciph;
-
- if(set_ciphers) {
- /* Set supported cipher lists */
- SSL_set_cipher_list(ssl, set_ciphers);
+ if (listen(listenfd, 64) < 0) {
+ syslog(LOG_ERR, "listen: %m");
+ return 1;
}
- if(get_ciphers) {
- /* Show supported cipher lists */
- sk=SSL_get_ciphers(ssl);
- for (i=0; i<sk_SSL_CIPHER_num(sk); i++) {
- BIO_puts(STDout,SSL_CIPHER_description( sk_SSL_CIPHER_value(sk,i), buf, 512));
- printf("%d: %s", i, buf);
+ init_id();
+
+ for (;;) {
+ webcgi_init(NULL);
+ if (connfd >= 0) close(connfd);
+
+ n = sizeof(clientsai);
+ if ((connfd = accept(listenfd, (struct sockaddr *)&clientsai, &n)) < 0) {
+// if ((errno != EINTR) && (errno != EAGAIN)) {
+// syslog(LOG_ERR, "accept: %m");
+// return 1;
+// }
+ sleep(1);
+ continue;
+ }
+
+ if (!wait_action_idle(10)) {
+// syslog(LOG_WARNING, "router is busy");
+ continue;
+ }
+
+ if (!check_wlaccess()) {
+ continue;
+ }
+
+ if (fork() == 0) {
+ close(listenfd);
+
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ setsockopt(connfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+ n = 1;
+ setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, (char *)&n, sizeof(n));
+
+ fcntl(connfd, F_SETFD, FD_CLOEXEC);
+
+ if (web_open()) handle_request();
+ web_close();
+ exit(0);
}
- if (STDout != NULL) BIO_free_all(STDout);
- }
- peer=SSL_get_peer_certificate(ssl);
- if (peer != NULL)
- {
- BIO_printf(bio_s_out,"Client certificate\n");
- PEM_write_bio_X509(bio_s_out,peer);
- X509_NAME_oneline(X509_get_subject_name(peer),buf,sizeof buf);
- BIO_printf(bio_s_out,"subject=%s\n",buf);
- X509_NAME_oneline(X509_get_issuer_name(peer),buf,sizeof buf);
- BIO_printf(bio_s_out,"issuer=%s\n",buf);
- X509_free(peer);
}
- if (SSL_get_shared_ciphers(ssl,buf,sizeof buf) != NULL)
- BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf);
-
- bio_stdout=BIO_new_fp(stdout,BIO_NOCLOSE);
- ciph=SSL_get_current_cipher(ssl);
- BIO_printf(bio_stdout,"%s%s, cipher %s %s\n",
- "",
- SSL_get_version(ssl),
- SSL_CIPHER_get_version(ciph),
- SSL_CIPHER_get_name(ciph));
+ close(listenfd);
+ return 0;
}
-#endif
diff --git a/release/src/router/httpd/httpd.h b/release/src/router/httpd/httpd.h
index 15c6da96..a9a3a962 100644
--- a/release/src/router/httpd/httpd.h
+++ b/release/src/router/httpd/httpd.h
@@ -1,111 +1,93 @@
-/*
- * milli_httpd - pretty small HTTP server
- *
- * Copyright 2005, Broadcom Corporation
- * All Rights Reserved.
- *
- * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
- * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
- * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
- *
- * $Id: httpd.h,v 1.13 2005/03/07 08:35:32 kanki Exp $
- */
-
-#include <cy_conf.h>
-#ifndef _httpd_h_
-#define _httpd_h_
-
-#if defined(DEBUG) && defined(DMALLOC)
-#include <dmalloc.h>
-#endif
+#ifndef __HTTPD_H__
+#define __HTTPD_H__
+
+extern struct sockaddr_in clientsai;
+extern int post;
+extern char *user_agent;
-#include <openssl/ssl.h>
-extern BIO *bio_err;
-
-// typedef BIO * webs_t;
-// #define wfgets(buf,len,fp) BIO_gets(fp,buf,len)
-// #define wfputc(c,fp) BIO_printf(fp,"%c",c)
-// #define wfputs(buf,fp) BIO_puts(fp,buf)
-// #define wfprintf(fp, args...) BIO_printf(fp, ## args)
-// #define wfwrite(buf,size,n,fp) BIO_write(fp,buf,n * size)
-// #define wfread(buf,size,n,fp) BIO_read(fp,buf,n * size)
-// #define wfflush(fp) BIO_flush(fp)
-// #define wfclose(fp) BIO_free_all(fp)
-//#else
-// typedef FILE * webs_t;
-// #define wfgets(buf,len,fp) fgets(buf,len,fp)
-// #define wfputc(c,fp) fputc(c,fp)
-// #define wfputs(buf,fp) fputs(buf,fp)
-// #define wfprintf(fp, args...) fprintf(fp, ## args)
-// #define wfwrite(buf,size,n,fp) fwrite(buf,size,n,fp)
-// #define wfread(buf,size,n,fp) fread(buf,size,n,fp)
-// #define wfflush(fp) fflush(fp)
-// #define wfclose(fp) fclose(fp)
-//#endif
-typedef FILE * webs_t;
-extern char * wfgets(char *buf, int len, FILE *fp);
-extern int wfputc(char c, FILE *fp);
-extern int wfputs(char *buf, FILE *fp);
-extern int wfprintf(FILE *fp, char *fmt,...);
-extern size_t wfwrite(char *buf, int size, int n, FILE *fp);
-extern size_t wfread(char *buf, int size, int n, FILE *fp);
-extern int wfflush(FILE *fp);
-extern int wfclose(FILE *fp);
-
-int do_ssl;
-/* Basic authorization userid and passwd limit */
-#define AUTH_MAX 64
-
-/* Generic MIME type handler */
struct mime_handler {
- char *pattern;
- char *mime_type;
- char *extra_header;
- void (*input)(char *path, FILE *stream, int len, char *boundary);
- void (*output)(char *path, FILE *stream);
- void (*auth)(char *userid, char *passwd, char *realm);
+ const char *pattern;
+ const char *mime_type;
+ int cache;
+ void (*input)(char *path, int len, char *boundary);
+ void (*output)(char *path);
+ int auth;
};
-extern struct mime_handler mime_handlers[];
-
-/* CGI helper functions */
-extern void init_cgi(char *query);
-extern char * get_cgi(char *name);
-extern void set_cgi(char *name, char *value);
-extern int count_cgi();
-
-/* Regular file handler */
-extern void do_file(char *path, webs_t stream);
-
-/* GoAhead 2.1 compatibility */
-//typedef FILE * webs_t;
-typedef char char_t;
-#define T(s) (s)
-#define __TMPVAR(x) tmpvar ## x
-#define _TMPVAR(x) __TMPVAR(x)
-#define TMPVAR _TMPVAR(__LINE__)
-#define websWrite(wp, fmt, args...) ({ int TMPVAR = wfprintf(wp, fmt, ## args); wfflush(wp); TMPVAR; })
-#define websDebugWrite(wp, fmt, args...) ({ error_value = 1; wfputs("<!--", wp); int TMPVAR = wfprintf(wp, fmt, ## args); wfputs("-->", wp); wfflush(wp); TMPVAR; })
-#define websError(wp, code, msg, args...) wfprintf(wp, msg, ## args)
-#define websHeader(wp) wfputs("<html lang=\"en\">", wp)
-#define websFooter(wp) wfputs("</html>", wp)
-#define websDone(wp, code) wfflush(wp)
-#define websGetVar(wp, var, default) (get_cgi(var) ? : default)
-#define websSetVar(wp, var, value) set_cgi(var, value)
-#define websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query) ({ do_ej(path, wp); fflush(wp); 1; })
-#define websWriteData(wp, buf, nChars) ({ int TMPVAR = wfwrite(buf, 1, nChars, wp); wfflush(wp); TMPVAR; })
-#define websWriteDataNonBlock websWriteData
-#define a_assert(a)
-
-extern int ejArgs(int argc, char_t **argv, char_t *fmt, ...);
-
-/* GoAhead 2.1 Embedded JavaScript compatibility */
-extern void do_ej(char *path, webs_t stream);
-struct ej_handler {
- char *pattern;
- int (*output)(int eid, webs_t wp, int argc, char_t **argv);
-};
-extern struct ej_handler ej_handlers[];
+extern const struct mime_handler mime_handlers[];
+
+
+//
+
+extern void do_file(char *path);
+
+
+// basic http i/o
+
+typedef enum {
+ WOF_NONE,
+ WOF_JAVASCRIPT,
+ WOF_HTML
+} wofilter_t;
+
+extern int web_getline(char *buffer, int max);
+extern int web_putc(char c);
+extern void web_puts(const char *buffer);
+extern void web_putj(const char *buffer);
+extern void web_puth(const char *buffer);
+extern int web_write(const char *buffer, int len);
+extern int web_read(void *buffer, int len);
+extern int web_read_x(void *b, int len);
+extern int web_eat(int max);
+extern int web_flush(void);
+extern int web_open(void);
+extern int web_close(void);
+
+extern int web_pipecmd(const char *cmd, wofilter_t wof);
+extern int web_putfile(const char *fname, wofilter_t wof);
+
+extern int _web_printf(wofilter_t wof, const char *format, ...);
+#define web_printf(args...) _web_printf(WOF_NONE, ##args)
+#define web_printfj(args...) _web_printf(WOF_JAVASCRIPT, ##args)
+#define web_printfh(args...) _web_printf(WOF_HTML, ##args)
+
+
+// http header handling
+extern const char mime_html[];
+extern const char mime_plain[];
+extern const char mime_javascript[];
+extern const char mime_octetstream[];
+extern const char mime_binary[];
+extern int header_sent;
-#endif /* _httpd_h_ */
+extern void send_header(int status, const char *header, const char *mime, int cache);
+extern void send_error(int status, const char *header, const char *text);
+extern void redirect(const char *path);
+extern int skip_header(int *len);
+
+
+// cgi handling
+
+extern void webcgi_init(char *query);
+extern char *webcgi_get(const char *name);
+extern void webcgi_set(char *name, char *value);
+
+#define webcgi_safeget(key, default) (webcgi_get(key) ? : (default))
+
+
+// asp file handing
+
+typedef struct {
+ const char *name;
+ void (*exec)(int argc, char **argv);
+} aspapi_t;
+
+extern const aspapi_t aspapi[];
+
+extern int parse_asp(const char *path);
+
+
+//
+extern void check_id(const char *url);
+
+#endif
diff --git a/release/src/router/httpd/key.pem b/release/src/router/httpd/key.pem
deleted file mode 100644
index 6e666d27..00000000
--- a/release/src/router/httpd/key.pem
+++ /dev/null
@@ -1,9 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIBOgIBAAJBALy3iYBtUiBdJT9HGogbiv9jRIV9qDySV/VREpdHjpFZ+ClJANlZ
-XajQU9eF9Np33XxM+w9QSxNMvwkRSOSV9IkCAwEAAQJAfanZreMd5N8hhllamXd9
-v0HixuE9vdfVKk2qC4JitPYHReAgpR4gGWiE917PLWoL1701rXbqlEkGcplePHm9
-YQIhAN153pKg1TM6nIm4dNym4SI4ViAfyanbn3ESedgUNlIPAiEA2iJldvc+ofZj
-SqlkfyPQNnHa5oLzgXlzbK5GP3T0h+cCIQC5vgKHMHF9dFNiQRtpDl/TpjG84Uvs
-s28lklwzdsgTywIgTVUYZ56rw7uX4+Y9zJ0jucmPc11FesdV1lfKa8DI2E0CICZZ
-wecsBOdY0s2uJn+SXm14f5/Ipysx2WFbaDCqcb/D
------END RSA PRIVATE KEY-----
diff --git a/release/src/router/httpd/log.c b/release/src/router/httpd/log.c
new file mode 100644
index 00000000..2aca2b23
--- /dev/null
+++ b/release/src/router/httpd/log.c
@@ -0,0 +1,76 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <ctype.h>
+
+static int logok(void)
+{
+ if (nvram_match("log_file", "1")) return 1;
+ resmsg_set("Internal logging disabled");
+ redirect("error.asp");
+ return 0;
+}
+
+void wo_viewlog(char *url)
+{
+ char *p;
+ char *c;
+ char s[128];
+ char t[128];
+ int n;
+
+ if (!logok()) return;
+
+ if ((p = webcgi_get("find")) != NULL) {
+ send_header(200, NULL, mime_plain, 0);
+ if (strlen(p) > 64) return;
+ c = t;
+ while (*p) {
+ switch (*p) {
+ case '<':
+ case '>':
+ case '|':
+ case '"':
+ case '\\':
+ *c++ = '\\';
+ *c++ = *p;
+ break;
+ default:
+ if (isprint(*p)) *c++ = *p;
+ break;
+ }
+ ++p;
+ }
+ *c = 0;
+ sprintf(s, "cat %s %s | grep -i \"%s\"", "/var/log/messages.0", "/var/log/messages", t);
+ web_pipecmd(s, WOF_NONE);
+ return;
+ }
+
+ if ((p = webcgi_get("which")) == NULL) return;
+ if (strcmp(p, "all") == 0) {
+ send_header(200, NULL, mime_plain, 0);
+ do_file("/var/log/messages.0");
+ do_file("/var/log/messages");
+ return;
+ }
+ if ((n = atoi(p)) > 0) {
+ send_header(200, NULL, mime_plain, 0);
+ sprintf(s, "cat %s %s | tail -n %d", "/var/log/messages.0", "/var/log/messages", n);
+ web_pipecmd(s, WOF_NONE);
+ }
+}
+
+void wo_syslog(char *url)
+{
+ if (!logok()) return;
+ send_header(200, NULL, mime_binary, 0);
+ do_file("/var/log/messages.0");
+ do_file("/var/log/messages");
+}
diff --git a/release/src/router/httpd/misc.c b/release/src/router/httpd/misc.c
new file mode 100644
index 00000000..8bc05772
--- /dev/null
+++ b/release/src/router/httpd/misc.c
@@ -0,0 +1,502 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <ctype.h>
+#include <sys/sysinfo.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/statfs.h>
+#include <netdb.h>
+#include <net/route.h>
+
+#include <wlioctl.h>
+#include <wlutils.h>
+
+// to javascript-safe string
+char *js_string(const char *s)
+{
+ unsigned char c;
+ char *buffer;
+ char *b;
+
+ if ((buffer = malloc((strlen(s) * 4) + 1)) != NULL) {
+ b = buffer;
+ while ((c = *s++) != 0) {
+ if ((c == '"') || (c == '\'') || (c == '\\') || (!isprint(c))) {
+ b += sprintf(b, "\\x%02x", c);
+ }
+ else {
+ *b++ = c;
+ }
+ }
+ *b = 0;
+ }
+ return buffer;
+}
+
+// to html-safe string
+char *html_string(const char *s)
+{
+ unsigned char c;
+ char *buffer;
+ char *b;
+
+ if ((buffer = malloc((strlen(s) * 6) + 1)) != NULL) {
+ b = buffer;
+ while ((c = *s++) != 0) {
+ if ((c == '&') || (c == '<') || (c == '>') || (c == '"') || (c == '\'') || (!isprint(c))) {
+ b += sprintf(b, "&#%d;", c);
+ }
+ else {
+ *b++ = c;
+ }
+ }
+ *b = 0;
+ }
+ return buffer;
+}
+
+// removes \r
+char *unix_string(const char *s)
+{
+ char *buffer;
+ char *b;
+ char c;
+
+ if ((buffer = malloc(strlen(s) + 1)) != NULL) {
+ b = buffer;
+ while ((c = *s++) != 0)
+ if (c != '\r') *b++ = c;
+ *b = 0;
+ }
+ return buffer;
+}
+
+// # days, ##:##:##
+char *reltime(char *buf, time_t t)
+{
+ int days;
+ int m;
+
+ if (t < 0) t = 0;
+ days = t / 86400;
+ m = t / 60;
+ sprintf(buf, "%d day%s, %02d:%02d:%02d", days, ((days==1) ? "" : "s"), ((m / 60) % 24), (m % 60), (int)(t % 60));
+ return buf;
+}
+
+int get_client_info(char *mac, char *ifname)
+{
+ FILE *f;
+ char s[256];
+ char ips[16];
+
+/*
+# cat /proc/net/arp
+IP address HW type Flags HW address Mask Device
+192.168.0.1 0x1 0x2 00:01:02:03:04:05 * vlan1
+192.168.1.5 0x1 0x2 00:05:06:07:08:09 * br0
+*/
+
+ if ((f = fopen("/proc/net/arp", "r")) != NULL) {
+ while (fgets(s, sizeof(s), f)) {
+ if (sscanf(s, "%15s %*s %*s %17s %*s %16s", ips, mac, ifname) == 3) {
+ if (inet_addr(ips) == clientsai.sin_addr.s_addr) {
+ fclose(f);
+ return 1;
+ }
+ }
+ }
+ fclose(f);
+ }
+ return 0;
+}
+
+
+
+
+
+// <% lanip(mode); %>
+// <mode>
+// 1 return first 3 octets (192.168.1)
+// 2 return last octet (1)
+// else return full (192.168.1.1)
+
+void asp_lanip(int argc, char **argv)
+{
+ char *nv, *p;
+ char s[64];
+ char mode;
+
+ mode = argc ? *argv[0] : 0;
+
+ if ((nv = nvram_get("lan_ipaddr")) != NULL) {
+ strcpy(s, nv);
+ if ((p = strrchr(s, '.')) != NULL) {
+ *p = 0;
+ web_puts((mode == '1') ? s : (mode == '2') ? (p + 1) : nv);
+ }
+ }
+}
+
+void asp_lipp(int argc, char **argv)
+{
+ char *one = "1";
+ asp_lanip(1, &one);
+}
+
+// <% psup(process); %>
+// returns 1 if process is running
+
+void asp_psup(int argc, char **argv)
+{
+ if (argc == 1) web_printf("%d", pidof(argv[0]) > 0);
+}
+
+/*
+# cat /proc/meminfo
+ total: used: free: shared: buffers: cached:
+Mem: 14872576 12877824 1994752 0 1236992 4837376
+Swap: 0 0 0
+MemTotal: 14524 kB
+MemFree: 1948 kB
+MemShared: 0 kB
+Buffers: 1208 kB
+Cached: 4724 kB
+SwapCached: 0 kB
+Active: 4364 kB
+Inactive: 2952 kB
+HighTotal: 0 kB
+HighFree: 0 kB
+LowTotal: 14524 kB
+LowFree: 1948 kB
+SwapTotal: 0 kB
+SwapFree: 0 kB
+
+*/
+
+typedef struct {
+ unsigned long total;
+ unsigned long free;
+ unsigned long shared;
+ unsigned long buffers;
+ unsigned long cached;
+ unsigned long swaptotal;
+ unsigned long swapfree;
+ unsigned long maxfreeram;
+} meminfo_t;
+
+static int get_memory(meminfo_t *m)
+{
+ FILE *f;
+ char s[128];
+ int ok = 0;
+
+ if ((f = fopen("/proc/meminfo", "r")) != NULL) {
+ while (fgets(s, sizeof(s), f)) {
+ if (strncmp(s, "Mem:", 4) == 0) {
+ if (sscanf(s + 6, "%ld %*d %ld %ld %ld %ld", &m->total, &m->free, &m->shared, &m->buffers, &m->cached) == 5)
+ ++ok;
+ }
+ else if (strncmp(s, "SwapTotal:", 10) == 0) {
+ m->swaptotal = strtoul(s + 12, NULL, 10) * 1024;
+ ++ok;
+ }
+ else if (strncmp(s, "SwapFree:", 9) == 0) {
+ m->swapfree = strtoul(s + 11, NULL, 10) * 1024;
+ ++ok;
+ break;
+ }
+ }
+ fclose(f);
+ }
+ if (ok != 3) {
+ memset(m, 0, sizeof(*m));
+ return 0;
+ }
+ m->maxfreeram = m->free;
+ if (nvram_match("t_cafree", "1")) m->maxfreeram += m->cached;
+ return 1;
+}
+
+void asp_sysinfo(int argc, char **argv)
+{
+ struct sysinfo si;
+ char s[64];
+ meminfo_t mem;
+
+ web_puts("\nsysinfo = {\n");
+ sysinfo(&si);
+ get_memory(&mem);
+ web_printf(
+ "\tuptime: %ld,\n"
+ "\tuptime_s: '%s',\n"
+ "\tloads: [%ld, %ld, %ld],\n"
+ "\ttotalram: %ld,\n"
+ "\tfreeram: %ld,\n"
+ "\tshareram: %ld,\n"
+ "\tbufferram: %ld,\n"
+ "\tcached: %ld,\n"
+ "\ttotalswap: %ld,\n"
+ "\tfreeswap: %ld,\n"
+ "\ttotalfreeram: %ld,\n"
+ "\tprocs: %d\n",
+ si.uptime,
+ reltime(s, si.uptime),
+ si.loads[0], si.loads[1], si.loads[2],
+ mem.total, mem.free,
+ mem.shared, mem.buffers, mem.cached,
+ mem.swaptotal, mem.swapfree,
+ mem.maxfreeram,
+ si.procs);
+ web_puts("};\n");
+}
+
+void asp_activeroutes(int argc, char **argv)
+{
+ FILE *f;
+ char s[512];
+ char dev[17];
+ unsigned long dest;
+ unsigned long gateway;
+ unsigned long flags;
+ unsigned long mask;
+ unsigned metric;
+ struct in_addr ia;
+ char s_dest[16];
+ char s_gateway[16];
+ char s_mask[16];
+ int n;
+
+ web_puts("\nactiveroutes = [");
+ n = 0;
+ if ((f = fopen("/proc/net/route", "r")) != NULL) {
+ while (fgets(s, sizeof(s), f)) {
+ if (sscanf(s, "%16s%lx%lx%lx%*s%*s%u%lx", dev, &dest, &gateway, &flags, &metric, &mask) != 6) continue;
+ if ((flags & RTF_UP) == 0) continue;
+ if (dest != 0) {
+ ia.s_addr = dest;
+ strcpy(s_dest, inet_ntoa(ia));
+ }
+ else {
+ strcpy(s_dest, "default");
+ }
+ if (gateway != 0) {
+ ia.s_addr = gateway;
+ strcpy(s_gateway, inet_ntoa(ia));
+ }
+ else {
+ strcpy(s_gateway, "*");
+ }
+ ia.s_addr = mask;
+ strcpy(s_mask, inet_ntoa(ia));
+ web_printf("%s['%s','%s','%s','%s',%u]", n ? "," : "", dev, s_dest, s_gateway, s_mask, metric);
+ ++n;
+ }
+ fclose(f);
+ }
+ web_puts("];\n");
+}
+
+void asp_cgi_get(int argc, char **argv)
+{
+ const char *v;
+ int i;
+
+ for (i = 0; i < argc; ++i) {
+ v = webcgi_get(argv[i]);
+ if (v) web_puts(v);
+ }
+}
+
+void asp_time(int argc, char **argv)
+{
+ time_t t;
+ char s[64];
+
+ t = time(NULL);
+ if (t < Y2K) {
+ web_puts("Not Available");
+ }
+ else {
+ strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
+ web_puts(s);
+ }
+}
+
+void asp_wanup(int argc, char **argv)
+{
+ web_puts(check_wanup() ? "1" : "0");
+}
+
+void asp_wanstatus(int argc, char **argv)
+{
+ const char *p;
+
+ if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) {
+ p = "Renewing...";
+ }
+ else if (check_wanup()) {
+ p = "Connected";
+ }
+ else if (f_exists("/var/lib/misc/wan.connecting")) {
+ p = "Connecting...";
+ }
+ else {
+ p = "Disconnected";
+ }
+ web_puts(p);
+}
+
+void asp_link_uptime(int argc, char **argv)
+{
+ struct sysinfo si;
+ char buf[64];
+ long uptime;
+
+ buf[0] = '-';
+ buf[1] = 0;
+ if (check_wanup()) {
+ sysinfo(&si);
+ if (f_read("/var/lib/misc/wantime", &uptime, sizeof(uptime)) == sizeof(uptime)) {
+ reltime(buf, si.uptime - uptime);
+ }
+ }
+ web_puts(buf);
+}
+
+void asp_rrule(int argc, char **argv)
+{
+ char s[32];
+ int i;
+
+ i = nvram_get_int("rruleN");
+ sprintf(s, "rrule%d", i);
+ web_puts("\nrrule = '");
+ web_putj(nvram_safe_get(s));
+ web_printf("';\nrruleN = %d;\n", i);
+}
+
+void asp_compmac(int argc, char **argv)
+{
+ char mac[32];
+ char ifname[32];
+
+ if (get_client_info(mac, ifname)) {
+ web_puts(mac);
+ }
+}
+
+void asp_ident(int argc, char **argv)
+{
+ web_puth(nvram_safe_get("router_name"));
+}
+
+void asp_statfs(int argc, char **argv)
+{
+ struct statfs sf;
+
+ if (argc != 2) return;
+
+ // used for /cifs/, /jffs/... if it returns squashfs type, assume it's not mounted
+ if ((statfs(argv[0], &sf) != 0) || (sf.f_type == 0x73717368))
+ memset(&sf, 0, sizeof(sf));
+
+ web_printf(
+ "\n%s = {\n"
+ "\tsize: %llu,\n"
+ "\tfree: %llu\n"
+ "};\n",
+ argv[1],
+ ((uint64_t)sf.f_bsize * sf.f_blocks),
+ ((uint64_t)sf.f_bsize * sf.f_bfree));
+}
+
+void asp_notice(int argc, char **argv)
+{
+ char s[256];
+ char buf[2048];
+
+ if (argc != 1) return;
+ snprintf(s, sizeof(s), "/var/notice/%s", argv[0]);
+ if (f_read_string(s, buf, sizeof(buf)) <= 0) return;
+ web_putj(buf);
+}
+
+void wo_wakeup(char *url)
+{
+ char *mac;
+ char *p;
+ char *end;
+
+ if ((mac = webcgi_get("mac")) != NULL) {
+ end = mac + strlen(mac);
+ while (mac < end) {
+ while ((*mac == ' ') || (*mac == '\t') || (*mac == '\r') || (*mac == '\n')) ++mac;
+ if (*mac == 0) break;
+
+ p = mac;
+ while ((*p != 0) && (*p != ' ') && (*p != '\r') && (*p != '\n')) ++p;
+ *p = 0;
+
+ eval("ether-wake", "-i", nvram_safe_get("lan_ifname"), mac);
+ mac = p + 1;
+ }
+ }
+ common_redirect();
+}
+
+void asp_dns(int argc, char **argv)
+{
+ char s[128];
+ int i;
+ const dns_list_t *dns;
+
+ dns = get_dns(); // static buffer
+ strcpy(s, "\ndns = [");
+ for (i = 0 ; i < dns->count; ++i) {
+ sprintf(s + strlen(s), "%s'%s:%u'", i ? "," : "", inet_ntoa(dns->dns[i].addr), dns->dns[i].port);
+ }
+ strcat(s, "];\n");
+ web_puts(s);
+}
+
+void wo_resolve(char *url)
+{
+ char *p;
+ char *ip;
+ struct hostent *he;
+ struct in_addr ia;
+ char comma;
+ char *js;
+
+ comma = ' ';
+ web_puts("\nresolve_data = [\n");
+ if ((p = webcgi_get("ip")) != NULL) {
+ while ((ip = strsep(&p, ",")) != NULL) {
+ ia.s_addr = inet_addr(ip);
+ he = gethostbyaddr(&ia, sizeof(ia), AF_INET);
+ js = js_string(he ? he->h_name : "");
+ web_printf("%c['%s','%s']", comma, inet_ntoa(ia), js);
+ free(js);
+ comma = ',';
+ }
+ }
+ web_puts("];\n");
+}
+
+
diff --git a/release/src/router/httpd/nvram.c b/release/src/router/httpd/nvram.c
new file mode 100644
index 00000000..beacf788
--- /dev/null
+++ b/release/src/router/httpd/nvram.c
@@ -0,0 +1,70 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+
+// <% nvram("x,y,z"); %> -> nvram = {'x': '1','y': '2','z': '3'};
+void asp_nvram(int argc, char **argv)
+{
+ char *list;
+ char *p, *k;
+ const char *v;
+
+ if ((argc != 1) || ((list = strdup(argv[0])) == NULL)) return;
+ web_puts("\nnvram = {\n");
+ p = list;
+ while ((k = strsep(&p, ",")) != NULL) {
+ if (*k == 0) continue;
+ v = nvram_get(k);
+ if (!v) {
+ v = "";
+ }
+ web_printf("\t%s: '", k);
+ web_putj(v);
+ web_puts("',\n");
+ }
+ free(list);
+
+ web_puts("\thttp_id: '");
+ web_putj(nvram_safe_get("http_id"));
+ web_puts("',\n");
+
+ web_puts("\tweb_mx: '");
+ web_putj(nvram_safe_get("web_mx"));
+ web_puts("',\n");
+
+ web_puts("\tweb_pb: '");
+ web_putj(nvram_safe_get("web_pb"));
+ web_puts("'};\n");
+}
+
+// <% nvramseq('foo', 'bar%d', 5, 8); %> -> foo = ['a','b','c'];
+void asp_nvramseq(int argc, char **argv)
+{
+ int i, e;
+ char s[256];
+
+ if (argc != 4) return;
+
+ web_printf("\n%s = [\n", argv[0]);
+ e = atoi(argv[3]);
+ for (i = atoi(argv[2]); i <= e; ++i) {
+ snprintf(s, sizeof(s), argv[1], i);
+ web_puts("'");
+ web_putj(nvram_safe_get(s));
+ web_puts((i == e) ? "'" : "',");
+ }
+ web_puts("];\n");
+}
+
+void asp_nv(int argc, char **argv)
+{
+ if (argc == 1) {
+ web_puts(nvram_safe_get(argv[0]));
+ }
+}
diff --git a/release/src/router/httpd/openssl.cnf b/release/src/router/httpd/openssl.cnf
deleted file mode 100644
index 12475c45..00000000
--- a/release/src/router/httpd/openssl.cnf
+++ /dev/null
@@ -1,263 +0,0 @@
-#
-# OpenSSL example configuration file.
-# This is mostly being used for generation of certificate requests.
-#
-
-# This definition stops the following lines choking if HOME isn't
-# defined.
-HOME = .
-RANDFILE = $ENV::HOME/.rnd
-
-# Extra OBJECT IDENTIFIER info:
-#oid_file = $ENV::HOME/.oid
-oid_section = new_oids
-
-# To use this configuration file with the "-extfile" option of the
-# "openssl x509" utility, name here the section containing the
-# X.509v3 extensions to use:
-# extensions =
-# (Alternatively, use a configuration file that has only
-# X.509v3 extensions in its main [= default] section.)
-
-[ new_oids ]
-
-# We can add new OIDs in here for use by 'ca' and 'req'.
-# Add a simple OID like this:
-# testoid1=1.2.3.4
-# Or use config file substitution like this:
-# testoid2=${testoid1}.5.6
-
-####################################################################
-[ ca ]
-default_ca = CA_default # The default ca section
-
-####################################################################
-[ CA_default ]
-
-#dir = ./demoCA # Where everything is kept
-dir = /usr/share # Where everything is kept
-certs = $dir/certs # Where the issued certs are kept
-crl_dir = $dir/crl # Where the issued crl are kept
-database = $dir/index.txt # database index file.
-new_certs_dir = $dir/newcerts # default place for new certs.
-
-certificate = $dir/cacert.pem # The CA certificate
-serial = $dir/serial # The current serial number
-crl = $dir/crl.pem # The current CRL
-private_key = $dir/private/cakey.pem# The private key
-RANDFILE = $dir/private/.rand # private random number file
-
-x509_extensions = usr_cert # The extentions to add to the cert
-
-# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
-# so this is commented out by default to leave a V1 CRL.
-# crl_extensions = crl_ext
-
-default_days = 3650 # how long to certify for
-default_crl_days= 30 # how long before next CRL
-default_md = md5 # which md to use.
-preserve = no # keep passed DN ordering
-
-# A few difference way of specifying how similar the request should look
-# For type CA, the listed attributes must be the same, and the optional
-# and supplied fields are just that :-)
-policy = policy_match
-
-# For the CA policy
-[ policy_match ]
-countryName = match
-stateOrProvinceName = match
-organizationName = match
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-# For the 'anything' policy
-# At this point in time, you must list all acceptable 'object'
-# types.
-[ policy_anything ]
-countryName = optional
-stateOrProvinceName = optional
-localityName = optional
-organizationName = optional
-organizationalUnitName = optional
-commonName = supplied
-emailAddress = optional
-
-####################################################################
-[ req ]
-default_bits = 2048
-default_keyfile = privkey.pem
-distinguished_name = req_distinguished_name
-attributes = req_attributes
-x509_extensions = v3_ca # The extentions to add to the self signed cert
-
-# Passwords for private keys if not present they will be prompted for
-#input_password = secret
-#output_password = secret
-
-# This sets a mask for permitted string types. There are several options.
-# default: PrintableString, T61String, BMPString.
-# pkix : PrintableString, BMPString.
-# utf8only: only UTF8Strings.
-# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
-# MASK:XXXX a literal mask value.
-# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
-# so use this option with caution!
-string_mask = nombstr
-
-req_extensions = v3_req # The extensions to add to a certificate request
-
-[ req_distinguished_name ]
-countryName = Country Name (2 letter code)
-countryName_default = GB
-countryName_value = US
-countryName_min = 2
-countryName_max = 2
-
-stateOrProvinceName = State or Province Name (full name)
-stateOrProvinceName_default = Berkshire
-stateOrProvinceName_value = California
-
-localityName = Locality Name (eg, city)
-localityName_default = Newbury
-localityName_value = Irvine
-
-0.organizationName = Organization Name (eg, company)
-0.organizationName_default = My Company Ltd
-0.organizationName_value = Cisco-Linksys, LLC
-
-# we can do this but it is not needed normally :-)
-#1.organizationName = Second Organization Name (eg, company)
-#1.organizationName_default = World Wide Web Pty Ltd
-
-organizationalUnitName = Organizational Unit Name (eg, section)
-organizationalUnitName_value = Division
-
-commonName = Common Name (eg, your name or your server\'s hostname)
-commonName_max = 64
-commonName_value = Linksys
-
-emailAddress = Email Address
-emailAddress_max = 40
-emailAddress_value = support@linksys.com
-
-# SET-ex3 = SET extension number 3
-
-[ req_attributes ]
-challengePassword = A challenge password
-challengePassword_min = 4
-challengePassword_max = 20
-challengePassword_value =
-
-unstructuredName = An optional company name
-unstructuredName_value =
-
-[ usr_cert ]
-
-# These extensions are added when 'ca' signs a request.
-
-# This goes against PKIX guidelines but some CAs do it and some software
-# requires this to avoid interpreting an end user certificate as a CA.
-
-basicConstraints=CA:FALSE
-
-# Here are some examples of the usage of nsCertType. If it is omitted
-# the certificate can be used for anything *except* object signing.
-
-# This is OK for an SSL server.
-# nsCertType = server
-
-# For an object signing certificate this would be used.
-# nsCertType = objsign
-
-# For normal client use this is typical
-# nsCertType = client, email
-
-# and for everything including object signing:
-# nsCertType = client, email, objsign
-
-# This is typical in keyUsage for a client certificate.
-# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
-
-# This will be displayed in Netscape's comment listbox.
-nsComment = "OpenSSL Generated Certificate"
-
-# PKIX recommendations harmless if included in all certificates.
-subjectKeyIdentifier=hash
-authorityKeyIdentifier=keyid,issuer:always
-
-# This stuff is for subjectAltName and issuerAltname.
-# Import the email address.
-# subjectAltName=email:copy
-
-# Copy subject details
-# issuerAltName=issuer:copy
-
-#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
-#nsBaseUrl
-#nsRevocationUrl
-#nsRenewalUrl
-#nsCaPolicyUrl
-#nsSslServerName
-
-[ v3_req ]
-
-# Extensions to add to a certificate request
-
-basicConstraints = CA:FALSE
-keyUsage = nonRepudiation, digitalSignature, keyEncipherment
-
-[ v3_ca ]
-
-
-# Extensions for a typical CA
-
-
-# PKIX recommendation.
-
-subjectKeyIdentifier=hash
-
-authorityKeyIdentifier=keyid:always,issuer:always
-
-# This is what PKIX recommends but some broken software chokes on critical
-# extensions.
-#basicConstraints = critical,CA:true
-# So we do this instead.
-basicConstraints = CA:true
-
-# Key usage: this is typical for a CA certificate. However since it will
-# prevent it being used as an test self-signed certificate it is best
-# left out by default.
-# keyUsage = cRLSign, keyCertSign
-
-# Some might want this also
-# nsCertType = sslCA, emailCA
-
-# Include email address in subject alt name: another PKIX recommendation
-# subjectAltName=email:copy
-# Copy issuer details
-# issuerAltName=issuer:copy
-
-# DER hex encoding of an extension: beware experts only!
-# obj=DER:02:03
-# Where 'obj' is a standard or added object
-# You can even override a supported extension:
-# basicConstraints= critical, DER:30:03:01:01:FF
-
-[ crl_ext ]
-
-# CRL extensions.
-# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
-
-# issuerAltName=issuer:copy
-authorityKeyIdentifier=keyid:always,issuer:always
-
-[ engine ]
-default = openssl
-# rsa = openssl
-# dsa = openssl
-# dh = openssl
-# rand = openssl
-# bn_mod_exp = openssl
-# bn_mod_exp_crt = openssl
diff --git a/release/src/router/httpd/parser.c b/release/src/router/httpd/parser.c
new file mode 100644
index 00000000..9dc4e94d
--- /dev/null
+++ b/release/src/router/httpd/parser.c
@@ -0,0 +1,187 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+
+#define DEBUG 1
+
+/*
+ <% ident(arg, "arg", 'arg'); %>
+
+ Syntax checking is very relaxed and all arguments are considered a
+ string. Example, the following are the same:
+
+ <% ident(foo); %>
+ <% ident('foo'); %>
+
+*/
+int parse_asp(const char *path)
+{
+ char *buffer;
+ char *cp;
+ char *a, *b, *c;
+ char x;
+ int argc;
+ char *argv[32];
+ char *ident;
+ const aspapi_t *api;
+
+#if TOMATO_N
+ // temp!!!
+ char npath[256];
+ int n;
+
+ if (!nvram_match("debug_npages", "0")) {
+ if (((a = strrchr(path, '.')) != NULL) && ((n = a - path) > 3) && (strncmp(a - 2, "-n", 2) != 0)) {
+ memcpy(npath, path, n);
+ memcpy(npath + n, "-n", 2);
+ strcpy(npath + n + 2, a);
+ if (f_exists(npath)) {
+ path = npath;
+ }
+ }
+ }
+#endif
+
+ if (f_read_alloc_string(path, &buffer, 128 * 1024) < 0) {
+ free(buffer);
+ if (!header_sent) send_error(500, NULL, "Read error");
+ return 0;
+ }
+
+ if (!header_sent) send_header(200, NULL, mime_html, 0);
+
+ // <% id(arg, arg); %>
+ cp = buffer;
+ while (*cp) {
+ if ((b = strstr(cp, "%>")) == NULL) {
+ web_puts(cp);
+ break;
+ }
+ *b = 0;
+
+ //xx <% <% %>
+ //xx %>
+
+ a = cp;
+ while ((c = strstr(a, "<%")) != NULL) {
+ a = c + 2;
+ }
+
+ if (a == cp) {
+ *b = '%';
+ b += 2;
+ web_write(cp, b - cp);
+ cp = b;
+ continue;
+ }
+
+ web_write(cp, (a - cp) - 2);
+
+ cp = b + 2;
+
+ while (*a == ' ') ++a;
+ ident = a;
+ while (((*a >= 'a') && (*a <= 'z')) || ((*a >= 'A') && (*a <= 'Z')) || ((*a >= '0') && (*a <= '9')) || (*a == '_')) {
+ ++a;
+ }
+ if (ident == a) {
+#ifdef DEBUG
+ syslog(LOG_WARNING, "Identifier not found in %s @%u", path, a - buffer);
+#endif
+ continue;
+ }
+ b = a;
+ while (*a == ' ') ++a;
+ if (*a++ != '(') {
+#ifdef DEBUG
+ syslog(LOG_WARNING, "Expecting ( in %s @%u", path, a - buffer);
+#endif
+ continue;
+ }
+ *b = 0;
+
+ // <% foo(123, "arg"); %>
+ // a -----^ ^--- null
+
+// printf("\n[[['%s'\n", ident);
+
+ argc = 0;
+ while (*a) {
+ while (*a == ' ') ++a;
+ if (*a == ')') {
+FINAL:
+ ++a;
+ while ((*a == ' ') || (*a == ';')) ++a;
+ if (*a != 0) break;
+
+ for (api = aspapi; api->name; ++api) {
+ if (strcmp(api->name, ident) == 0) {
+ api->exec(argc, argv);
+ break;
+ }
+ }
+
+ a = NULL;
+/*
+ int z;
+ for (z = 0; z < argc; ++z) {
+ printf(" %d '%s'\n", z, argv[z]);
+ }
+*/
+ break;
+ }
+
+ if (argc >= 32) {
+#ifdef DEBUG
+ syslog(LOG_WARNING, "Error while parsing arguments in %s @%u", path, a - buffer);
+#endif
+ break;
+ }
+
+ if ((*a == '"') || (*a == '\'')) {
+ x = *a;
+ argv[argc++] = a + 1;
+ while ((*++a != x) && (*a != 0)) {
+ if (*a == '\\') {
+ if (*++a == 0) break;
+ *(a - 1) = *a;
+ }
+ }
+ if (*a == 0) break;
+ *a++ = 0;
+ }
+ else {
+ argv[argc++] = a;
+ while ((*a != ',') && (*a != ')') && (*a != ' ') && (*a != 0)) ++a;
+ }
+ while (*a == ' ') ++a;
+ if (*a == ')') {
+ *a = 0;
+ goto FINAL;
+ }
+ if (*a != ',') break;
+ *a++ = 0;
+ }
+
+#ifdef DEBUG
+ if (a != NULL) syslog(LOG_WARNING, "Error while parsing arguments in %s @%u", path, a - buffer);
+#endif
+
+// printf("argc=%d]]]\n", argc);
+ }
+
+
+ free(buffer);
+ return 1;
+}
+
+void wo_asp(char *path)
+{
+ parse_asp(path);
+}
diff --git a/release/src/router/httpd/prebuilt/ezc.o b/release/src/router/httpd/prebuilt/ezc.o
deleted file mode 100644
index 4e7b4659..00000000
--- a/release/src/router/httpd/prebuilt/ezc.o
+++ /dev/null
Binary files differ
diff --git a/release/src/router/httpd/tomato.c b/release/src/router/httpd/tomato.c
new file mode 100644
index 00000000..01b912dc
--- /dev/null
+++ b/release/src/router/httpd/tomato.c
@@ -0,0 +1,935 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2010 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <sys/sysinfo.h>
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+
+// #define DEBUG_NOEXECSERVICE
+// #define DEBUG_NVRAMSET(k, v) cprintf("nvram set %s=%s\n", k, v);
+#define DEBUG_NVRAMSET(k, v) do { } while(0);
+
+
+char *post_buf = NULL;
+int rboot = 0;
+extern int post;
+
+static void asp_css(int argc, char **argv);
+static void asp_resmsg(int argc, char **argv);
+
+//
+static void wo_tomato(char *url);
+static void wo_update(char *url);
+static void wo_service(char *url);
+static void wo_shutdown(char *url);
+static void wo_nvcommit(char *url);
+// static void wo_logout(char *url);
+
+
+// ----------------------------------------------------------------------------
+
+
+void exec_service(const char *action)
+{
+ int i;
+
+ _dprintf("exec_service: %s\n", action);
+
+ i = 10;
+ while ((!nvram_match("action_service", "")) && (i-- > 0)) {
+ _dprintf("%s: waiting before %d\n", __FUNCTION__, i);
+ sleep(1);
+ }
+
+ nvram_set("action_service", action);
+ kill(1, SIGUSR1);
+
+ i = 3;
+ while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) {
+ _dprintf("%s: waiting after %d\n", __FUNCTION__, i);
+ sleep(1);
+ }
+
+/*
+ if (atoi(webcgi_safeget("_service_wait", ""))) {
+ i = 10;
+ while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) {
+ _dprintf("%s: waiting after %d\n", __FUNCTION__, i);
+ sleep(1);
+ }
+ }
+*/
+}
+
+static void wi_generic_noid(char *url, int len, char *boundary)
+{
+ if (post == 1) {
+ if (len >= (32 * 1024)) {
+// syslog(LOG_WARNING, "POST max");
+ exit(1);
+ }
+
+ if (!post_buf) free(post_buf);
+ if ((post_buf = malloc(len + 1)) == NULL) {
+// syslog(LOG_CRIT, "Unable to allocate post buffer");
+ exit(1);
+ }
+
+ if (web_read_x(post_buf, len) != len) {
+ exit(1);
+ }
+ post_buf[len] = 0;
+ webcgi_init(post_buf);
+ }
+}
+
+void wi_generic(char *url, int len, char *boundary)
+{
+ wi_generic_noid(url, len, boundary);
+ check_id(url);
+}
+
+static void wo_blank(char *url)
+{
+ web_puts("\n\n\n\n");
+}
+
+static void wo_favicon(char *url)
+{
+ send_header(200, NULL, "image/vnd.microsoft.icon", 0);
+ do_file(url);
+/*
+ if (nvram_match("web_favicon", "1")) {
+ send_header(200, NULL, "image/vnd.microsoft.icon", 0);
+ do_file(url);
+ }
+ else {
+ send_error(404, NULL, NULL);
+ }
+*/
+}
+
+static void wo_cfe(char *url)
+{
+ do_file("/dev/mtd/0ro");
+}
+
+static void wo_nvram(char *url)
+{
+ web_pipecmd("nvram show", WOF_NONE);
+}
+
+static void wo_iptables(char *url)
+{
+ web_pipecmd("iptables -nvL; iptables -t nat -nvL; iptables -t mangle -nvL", WOF_NONE);
+}
+
+/*
+static void wo_spin(char *url)
+{
+ char s[64];
+
+ strlcpy(s, nvram_safe_get("web_css"), sizeof(s));
+ strlcat(s, "_spin.gif", sizeof(s));
+ if (f_exists(s)) do_file(s);
+ else do_file("_spin.gif");
+}
+*/
+
+void common_redirect(void)
+{
+ if (atoi(webcgi_safeget("_ajax", ""))) {
+ send_header(200, NULL, mime_html, 0);
+ web_puts("OK");
+ }
+ else {
+ redirect(webcgi_safeget("_redirect", "/"));
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+const struct mime_handler mime_handlers[] = {
+ { "update.cgi", mime_javascript, 0, wi_generic, wo_update, 1 },
+ { "tomato.cgi", NULL, 0, wi_generic, wo_tomato, 1 },
+
+ { "debug.js", mime_javascript, 5, wi_generic_noid, wo_blank, 1 }, // while debugging
+ { "cfe/*.bin", mime_binary, 0, wi_generic, wo_cfe, 1 },
+ { "nvram/*.txt", mime_binary, 0, wi_generic, wo_nvram, 1 },
+ { "ipt/*.txt", mime_binary, 0, wi_generic, wo_iptables, 1 },
+
+ { "cfg/*.cfg", NULL, 0, wi_generic, wo_backup, 1 },
+ { "cfg/restore.cgi", mime_html, 0, wi_restore, wo_restore, 1 },
+ { "cfg/defaults.cgi", NULL, 0, wi_generic, wo_defaults, 1 },
+
+ { "bwm/*.gz", NULL, 0, wi_generic, wo_bwmbackup, 1 },
+ { "bwm/restore.cgi", NULL, 0, wi_bwmrestore, wo_bwmrestore, 1 },
+
+ { "logs/view.cgi", NULL, 0, wi_generic, wo_viewlog, 1 },
+ { "logs/*.txt", NULL, 0, wi_generic, wo_syslog, 1 },
+
+ { "logout.asp", NULL, 0, wi_generic, wo_asp, 1 },
+ { "clearcookies.asp", NULL, 0, wi_generic, wo_asp, 1 },
+
+// { "spin.gif", NULL, 0, wi_generic_noid, wo_spin, 1 },
+
+ { "**.asp", NULL, 0, wi_generic_noid, wo_asp, 1 },
+ { "**.css", "text/css", 2, wi_generic_noid, do_file, 1 },
+ { "**.htm", mime_html, 2, wi_generic_noid, do_file, 1 },
+ { "**.gif", "image/gif", 5, wi_generic_noid, do_file, 1 },
+ { "**.jpg", "image/jpeg", 5, wi_generic_noid, do_file, 1 },
+ { "**.png", "image/png", 5, wi_generic_noid, do_file, 1 },
+ { "**.js", mime_javascript, 2, wi_generic_noid, do_file, 1 },
+ { "**.jsx", mime_javascript, 0, wi_generic, wo_asp, 1 },
+ { "**.svg", "image/svg+xml", 2, wi_generic_noid, do_file, 1 },
+ { "**.txt", mime_plain, 2, wi_generic_noid, do_file, 1 },
+ { "**.bin", mime_binary, 0, wi_generic_noid, do_file, 1 },
+ { "**.bino", mime_octetstream, 0, wi_generic_noid, do_file, 1 },
+ { "favicon.ico", NULL, 5, wi_generic_noid, wo_favicon, 1 },
+
+
+ { "dhcpc.cgi", NULL, 0, wi_generic, wo_dhcpc, 1 },
+ { "dhcpd.cgi", mime_javascript, 0, wi_generic, wo_dhcpd, 1 },
+ { "nvcommit.cgi", NULL, 0, wi_generic, wo_nvcommit, 1 },
+ { "ping.cgi", mime_javascript, 0, wi_generic, wo_ping, 1 },
+ { "trace.cgi", mime_javascript, 0, wi_generic, wo_trace, 1 },
+ { "upgrade.cgi", mime_html, 0, wi_upgrade, wo_flash, 1 },
+ { "upnp.cgi", NULL, 0, wi_generic, wo_upnp, 1 },
+ { "wakeup.cgi", NULL, 0, wi_generic, wo_wakeup, 1 },
+ { "wlmnoise.cgi", mime_html, 0, wi_generic, wo_wlmnoise, 1 },
+ { "wlradio.cgi", NULL, 0, wi_generic, wo_wlradio, 1 },
+ { "resolve.cgi", mime_javascript, 0, wi_generic, wo_resolve, 1 },
+ { "expct.cgi", mime_html, 0, wi_generic, wo_expct, 1 },
+ { "service.cgi", NULL, 0, wi_generic, wo_service, 1 },
+// { "logout.cgi", NULL, 0, wi_generic, wo_logout, 0 }, // see httpd.c
+ { "shutdown.cgi", mime_html, 0, wi_generic, wo_shutdown, 1 },
+
+#ifdef BLACKHOLE
+ { "blackhole.cgi", NULL, 0, wi_blackhole, NULL, 1 },
+#endif
+// { "test", mime_html, 0, wi_generic, wo_test, 1 },
+ { NULL, NULL, 0, NULL, NULL, 1 }
+};
+
+const aspapi_t aspapi[] = {
+ { "activeroutes", asp_activeroutes },
+ { "arplist", asp_arplist },
+ { "bandwidth", asp_bandwidth },
+ { "build_time", asp_build_time },
+ { "cgi_get", asp_cgi_get },
+ { "compmac", asp_compmac },
+ { "ctcount", asp_ctcount },
+ { "ctdump", asp_ctdump },
+ { "ddnsx", asp_ddnsx },
+ { "devlist", asp_devlist },
+ { "dhcpc_time", asp_dhcpc_time },
+ { "dns", asp_dns },
+ { "ident", asp_ident },
+ { "lanip", asp_lanip },
+ { "layer7", asp_layer7 },
+ { "link_uptime", asp_link_uptime },
+ { "lipp", asp_lipp },
+ { "netdev", asp_netdev },
+ { "notice", asp_notice },
+ { "nv", asp_nv },
+ { "nvram", asp_nvram },
+ { "nvramseq", asp_nvramseq },
+ { "psup", asp_psup },
+ { "qrate", asp_qrate },
+ { "resmsg", asp_resmsg },
+ { "rrule", asp_rrule },
+ { "statfs", asp_statfs },
+ { "sysinfo", asp_sysinfo },
+ { "time", asp_time },
+ { "upnpinfo", asp_upnpinfo },
+ { "version", asp_version },
+ { "wanstatus", asp_wanstatus },
+ { "wanup", asp_wanup },
+ { "wlchannel", asp_wlchannel },
+ { "wlclient", asp_wlclient },
+ { "wlcrssi", asp_wlcrssi },
+ { "wlnoise", asp_wlnoise },
+ { "wlradio", asp_wlradio },
+ { "wlscan", asp_wlscan },
+ { "css", asp_css },
+ { NULL, NULL }
+};
+
+// -----------------------------------------------------------------------------
+
+static void asp_css(int argc, char **argv)
+{
+ const char *css = nvram_safe_get("web_css");
+
+ if (strcmp(css, "tomato") != 0) {
+ web_printf("<link rel='stylesheet' type='text/css' href='%s.css'>", css);
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+const char *resmsg_get(void)
+{
+ return webcgi_safeget("resmsg", "");
+}
+
+void resmsg_set(const char *msg)
+{
+ webcgi_set("resmsg", strdup(msg)); // m ok
+}
+
+int resmsg_fread(const char *fname)
+{
+ char s[256];
+ char *p;
+
+ f_read_string(fname, s, sizeof(s));
+ if ((p = strchr(s, '\n')) != NULL) *p = 0;
+ if (s[0]) {
+ resmsg_set(s);
+ return 1;
+ }
+ return 0;
+}
+
+static void asp_resmsg(int argc, char **argv)
+{
+ char *p;
+
+ if ((p = js_string(webcgi_safeget("resmsg", (argc > 0) ? argv[0] : ""))) == NULL) return;
+ web_printf("\nresmsg='%s';\n", p);
+ free(p);
+}
+
+// ----------------------------------------------------------------------------
+
+// verification... simple sanity checks. UI should verify all fields.
+
+// todo: move and re-use for filtering - zzz
+
+typedef union {
+ int i;
+ long l;
+ const char *s;
+} nvset_varg_t;
+
+typedef struct {
+ const char *name;
+ enum {
+ VT_NONE, // no checking
+ VT_LENGTH, // check length of string
+ VT_TEXT, // strip \r, check length of string
+ VT_RANGE, // expect an integer, check range
+ VT_IP, // expect an ip address
+ VT_MAC, // expect a mac address
+ VT_TEMP // no checks, no commit
+ } vtype;
+ nvset_varg_t va;
+ nvset_varg_t vb;
+} nvset_t;
+
+
+#define V_NONE VT_NONE, { }, { }
+#define V_01 VT_RANGE, { .l = 0 }, { .l = 1 }
+#define V_PORT VT_RANGE, { .l = 2 }, { .l = 65535 }
+#define V_ONOFF VT_LENGTH, { .i = 2 }, { .i = 3 }
+#define V_WORD VT_LENGTH, { .i = 1 }, { .i = 16 }
+#define V_LENGTH(min, max) VT_LENGTH, { .i = min }, { .i = max }
+#define V_TEXT(min, max) VT_TEXT, { .i = min }, { .i = max }
+#define V_RANGE(min, max) VT_RANGE, { .l = min }, { .l = max }
+#define V_IP VT_IP, { }, { }
+#define V_OCTET VT_RANGE, { .l = 0 }, { .l = 255 }
+#define V_NUM VT_RANGE, { .l = 0 }, { .l = 0x7FFFFFFF }
+#define V_TEMP VT_TEMP, { }, { }
+
+static const nvset_t nvset_list[] = {
+
+// basic-ident
+ { "router_name", V_LENGTH(0, 32) },
+ { "wan_hostname", V_LENGTH(0, 32) },
+ { "wan_domain", V_LENGTH(0, 32) },
+
+// basic-time
+ { "tm_tz", V_LENGTH(1, 64) }, // PST8PDT
+ { "tm_sel", V_LENGTH(1, 64) }, // PST8PDT
+ { "tm_dst", V_01 },
+ { "ntp_updates", V_RANGE(-1, 24) },
+ { "ntp_tdod", V_01 },
+ { "ntp_server", V_LENGTH(1, 150) }, // x y z
+ { "ntp_kiss", V_LENGTH(0, 255) },
+
+// basic-static
+ { "dhcpd_static", V_LENGTH(0, 106*101)}, // 106 (max chars per entry) x 100 entries
+
+// basic-ddns
+ { "ddnsx0", V_LENGTH(0, 2048) },
+ { "ddnsx1", V_LENGTH(0, 2048) },
+ { "ddnsx0_cache", V_LENGTH(0, 1) }, // only to clear
+ { "ddnsx1_cache", V_LENGTH(0, 1) },
+ { "ddnsx_ip", V_LENGTH(0, 32) },
+ { "ddnsx_save", V_01 },
+ { "ddnsx_refresh", V_RANGE(0, 365) },
+
+// basic-network
+ // WAN
+ { "wan_proto", V_LENGTH(1, 16) }, // disabled, dhcp, static, pppoe, pptp, l2tp
+ { "wan_ipaddr", V_IP },
+ { "wan_netmask", V_IP },
+ { "wan_gateway", V_IP },
+ { "hb_server_ip", V_LENGTH(0, 32) },
+ { "l2tp_server_ip", V_IP },
+ { "pptp_server_ip", V_IP },
+ { "ppp_username", V_LENGTH(0, 60) },
+ { "ppp_passwd", V_LENGTH(0, 60) },
+ { "ppp_service", V_LENGTH(0, 50) },
+ { "ppp_demand", V_01 },
+ { "ppp_idletime", V_RANGE(0, 1440) },
+ { "ppp_redialperiod", V_RANGE(1, 86400) },
+ { "mtu_enable", V_01 },
+ { "wan_mtu", V_RANGE(576, 1500) },
+ { "wan_islan", V_01 },
+
+ // LAN
+ { "lan_ipaddr", V_IP },
+ { "lan_netmask", V_IP },
+ { "lan_gateway", V_IP },
+ { "wan_dns", V_LENGTH(0, 50) }, // ip ip ip
+ { "lan_proto", V_WORD }, // static, dhcp
+ { "dhcp_start", V_RANGE(1, 254) }, // remove !
+ { "dhcp_num", V_RANGE(1, 255) }, // remove !
+ { "dhcpd_startip", V_IP },
+ { "dhcpd_endip", V_IP },
+ { "dhcp_lease", V_RANGE(1, 10080) },
+ { "wan_wins", V_IP },
+
+ // wireless
+ { "wl_radio", V_01 },
+ { "wl_mode", V_LENGTH(2, 3) }, // ap, sta, wet, wds
+ { "wl_net_mode", V_LENGTH(5, 8) }, // disabled, mixed, b-only, g-only, bg-mixed, n-only [speedbooster]
+ { "wl_ssid", V_LENGTH(1, 32) },
+ { "wl_closed", V_01 },
+ { "wl_channel", V_RANGE(1, 14) },
+#if TOMATO_N
+ // ! update
+#endif
+
+ { "security_mode2", V_LENGTH(1, 32) }, // disabled, radius, wep, wpa_personal, wpa_enterprise, wpa2_personal, wpa2_enterprise
+ { "wl_radius_ipaddr", V_IP },
+ { "wl_radius_port", V_PORT },
+ { "wl_radius_key", V_LENGTH(1, 64) },
+ { "wl_wep_bit", V_RANGE(64, 128) }, // 64 or 128
+ { "wl_passphrase", V_LENGTH(0, 20) },
+ { "wl_key", V_RANGE(1, 4) },
+ { "wl_key1", V_LENGTH(0, 26) },
+ { "wl_key2", V_LENGTH(0, 26) },
+ { "wl_key3", V_LENGTH(0, 26) },
+ { "wl_key4", V_LENGTH(0, 26) },
+ { "wl_crypto", V_LENGTH(3, 8) }, // tkip, aes, tkip+aes
+ { "wl_wpa_psk", V_LENGTH(8, 64) },
+ { "wl_wpa_gtk_rekey", V_RANGE(60, 7200) },
+
+ { "wl_lazywds", V_01 },
+ { "wl_wds", V_LENGTH(0, 180) }, // mac mac mac (x 10)
+
+ { "security_mode", V_LENGTH(1, 32) }, // disabled, radius, wpa, psk,wep, wpa2, psk2, wpa wpa2, psk psk2
+ { "wds_enable", V_01 },
+ { "wl_gmode", V_RANGE(-1, 6) },
+ { "wl_wep", V_LENGTH(1, 32) }, // off, on, restricted,tkip,aes,tkip+aes
+ { "wl_akm", V_LENGTH(0, 32) }, // wpa, wpa2, psk, psk2, wpa wpa2, psk psk2, ""
+ { "wl_auth_mode", V_LENGTH(4, 6) }, // none, radius
+
+#if TOMATO_N
+ { "wl_nmode", V_NONE },
+ { "wl_nreqd", V_NONE },
+#endif
+
+// basic-wfilter
+ { "wl_macmode", V_NONE }, // allow, deny, disabled
+ { "wl_maclist", V_LENGTH(0, 18*201) }, // 18 x 200 (11:22:33:44:55:66 ...)
+ { "macnames", V_LENGTH(0, 62*201) }, // 62 (12+1+48+1) x 50 (112233445566<..>) todo: re-use -- zzz
+
+// advanced-ctnf
+ { "ct_max", V_RANGE(128, 10240) },
+ { "ct_tcp_timeout", V_LENGTH(20, 70) },
+ { "ct_udp_timeout", V_LENGTH(5, 15) },
+ { "nf_ttl", V_RANGE(-10, 10) },
+ { "nf_l7in", V_01 },
+ { "nf_rtsp", V_01 },
+ { "nf_pptp", V_01 },
+ { "nf_h323", V_01 },
+ { "nf_ftp", V_01 },
+
+// advanced-dhcpdns
+ { "dhcpd_slt", V_RANGE(-1, 43200) }, // -1=infinite, 0=follow normal lease time, >=1 custom
+ { "dhcpd_dmdns", V_01 },
+ { "dhcpd_lmax", V_NUM },
+ { "dhcpd_gwmode", V_NUM },
+ { "dns_addget", V_01 },
+ { "dns_intcpt", V_01 },
+ { "dhcpc_minpkt", V_01 },
+ { "dnsmasq_custom", V_TEXT(0, 2048) },
+// { "dnsmasq_norw", V_01 },
+
+// advanced-firewall
+ { "block_wan", V_01 },
+ { "multicast_pass", V_01 },
+ { "block_loopback", V_01 },
+ { "nf_loopback", V_NUM },
+ { "ne_syncookies", V_01 },
+
+// advanced-misc
+ { "wait_time", V_RANGE(3, 20) },
+ { "wan_speed", V_RANGE(0, 4) },
+
+// advanced-mac
+ { "mac_wan", V_LENGTH(0, 17) },
+ { "mac_wl", V_LENGTH(0, 17) },
+
+// advanced-routing
+ { "routes_static", V_LENGTH(0, 2048) },
+ { "lan_stp", V_RANGE(0, 1) },
+ { "wk_mode", V_LENGTH(1, 32) }, // gateway, router
+ { "dr_setting", V_RANGE(0, 3) },
+ { "dr_lan_tx", V_LENGTH(0, 32) },
+ { "dr_lan_rx", V_LENGTH(0, 32) },
+ { "dr_wan_tx", V_LENGTH(0, 32) },
+ { "dr_wan_rx", V_LENGTH(0, 32) },
+
+// advanced-wireless
+ { "wl_afterburner", V_LENGTH(2, 4) }, // off, on, auto
+ { "wl_auth", V_01 },
+ { "wl_rateset", V_LENGTH(2, 7) }, // all, default, 12
+ { "wl_rate", V_RANGE(0, 54 * 1000 * 1000) },
+ { "wl_mrate", V_RANGE(0, 54 * 1000 * 1000) },
+ { "wl_gmode_protection",V_LENGTH(3, 4) }, // off, auto
+ { "wl_frameburst", V_ONOFF }, // off, on
+ { "wl_bcn", V_RANGE(1, 65535) },
+ { "wl_dtim", V_RANGE(1, 255) },
+ { "wl_frag", V_RANGE(256, 2346) },
+ { "wl_rts", V_RANGE(0, 2347) },
+ { "wl_ap_isolate", V_01 },
+ { "wl_plcphdr", V_LENGTH(4, 5) }, // long, short
+ { "wl_antdiv", V_RANGE(0, 3) },
+ { "wl_txant", V_RANGE(0, 3) },
+ { "wl_txpwr", V_RANGE(0, 255) },
+ { "wl_wme", V_ONOFF }, // off, on
+ { "wl_wme_no_ack", V_ONOFF }, // off, on
+ { "wl_maxassoc", V_RANGE(0, 255) },
+ { "wl_distance", V_LENGTH(0, 5) }, // "", 1-99999
+ { "wlx_hpamp", V_01 },
+ { "wlx_hperx", V_01 },
+
+#if TOMATO_N
+ { "wl_nmode_protection",V_WORD, }, // off, auto
+ { "wl_nmcsidx", V_RANGE(-2, 15), }, // -2 - 15
+#endif
+
+// forward-dmz
+ { "dmz_enable", V_01 },
+ { "dmz_ipaddr", V_LENGTH(0, 15) },
+ { "dmz_sip", V_LENGTH(0, 512) },
+
+// forward-upnp
+ { "upnp_enable", V_NUM },
+#ifndef USE_MINIUPNPD
+ { "upnp_mnp", V_01 },
+// { "upnp_config", V_01 },
+ { "upnp_ssdp_interval", V_RANGE(10, 9999) },
+ { "upnp_max_age", V_RANGE(5, 9999) },
+#endif
+
+// forward-basic
+ { "portforward", V_LENGTH(0, 4096) },
+
+// forward-triggered
+ { "trigforward", V_LENGTH(0, 4096) },
+
+
+// access restriction
+ { "rruleN", V_RANGE(0, 49) },
+// { "rrule##", V_LENGTH(0, 2048) }, // in save_variables()
+
+// admin-access
+ { "http_enable", V_01 },
+ { "https_enable", V_01 },
+ { "https_crt_save", V_01 },
+ { "https_crt_cn", V_LENGTH(0, 64) },
+ { "https_crt_gen", V_TEMP },
+ { "remote_management", V_01 },
+ { "remote_mgt_https", V_01 },
+ { "http_lanport", V_PORT },
+ { "https_lanport", V_PORT },
+ { "web_wl_filter", V_01 },
+ { "web_css", V_LENGTH(1, 32) },
+ { "web_mx", V_LENGTH(0, 128) },
+ { "http_wanport", V_PORT },
+ { "telnetd_eas", V_01 },
+ { "telnetd_port", V_PORT },
+ { "sshd_eas", V_01 },
+ { "sshd_pass", V_01 },
+ { "sshd_port", V_PORT },
+ { "sshd_remote", V_01 },
+ { "sshd_rport", V_PORT },
+ { "sshd_authkeys", V_TEXT(0, 4096) },
+ { "rmgt_sip", V_LENGTH(0, 512) },
+ { "ne_shlimit", V_TEXT(1, 50) },
+
+// admin-bwm
+ { "rstats_enable", V_01 },
+ { "rstats_path", V_LENGTH(0, 48) },
+ { "rstats_stime", V_RANGE(1, 168) },
+ { "rstats_offset", V_RANGE(1, 31) },
+ { "rstats_exclude", V_LENGTH(0, 64) },
+ { "rstats_sshut", V_01 },
+ { "rstats_bak", V_01 },
+
+// admin-buttons
+ { "sesx_led", V_RANGE(0, 255) }, // amber, white, aoss
+ { "sesx_b0", V_RANGE(0, 4) }, // 0-4: toggle wireless, reboot, shutdown, script
+ { "sesx_b1", V_RANGE(0, 4) }, // "
+ { "sesx_b2", V_RANGE(0, 4) }, // "
+ { "sesx_b3", V_RANGE(0, 4) }, // "
+ { "sesx_script", V_TEXT(0, 1024) }, //
+ { "script_brau", V_TEXT(0, 1024) }, //
+
+// admin-debug
+ { "debug_nocommit", V_01 },
+ { "debug_cprintf", V_01 },
+ { "debug_cprintf_file", V_01 },
+// { "debug_keepfiles", V_01 },
+ { "debug_ddns", V_01 },
+ { "debug_norestart", V_TEXT(0, 128) },
+ { "console_loglevel", V_RANGE(1, 8) },
+ { "t_cafree", V_01 },
+ { "t_hidelr", V_01 },
+
+// admin-sched
+ { "sch_rboot", V_TEXT(0, 64) },
+ { "sch_rcon", V_TEXT(0, 64) },
+ { "sch_c1", V_TEXT(0, 64) },
+ { "sch_c1_cmd", V_TEXT(0, 2048) },
+ { "sch_c2", V_TEXT(0, 64) },
+ { "sch_c2_cmd", V_TEXT(0, 2048) },
+ { "sch_c3", V_TEXT(0, 64) },
+ { "sch_c3_cmd", V_TEXT(0, 2048) },
+
+// admin-scripts
+ { "script_init", V_TEXT(0, 4096) },
+ { "script_shut", V_TEXT(0, 4096) },
+ { "script_fire", V_TEXT(0, 8192) },
+ { "script_wanup", V_TEXT(0, 4096) },
+
+// admin-log
+ { "log_remote", V_01 },
+ { "log_remoteip", V_IP },
+ { "log_remoteport", V_PORT },
+ { "log_file", V_01 },
+ { "log_limit", V_RANGE(0, 2400) },
+ { "log_in", V_RANGE(0, 3) },
+ { "log_out", V_RANGE(0, 3) },
+ { "log_mark", V_RANGE(0, 1440) },
+ { "log_events", V_TEXT(0, 32) }, // "acre,crond,ntp"
+
+// admin-cifs
+ { "cifs1", V_LENGTH(1, 1024) },
+ { "cifs2", V_LENGTH(1, 1024) },
+
+// admin-jffs2
+ { "jffs2_on", V_01 },
+ { "jffs2_exec", V_LENGTH(0, 64) },
+ { "jffs2_format", V_01 },
+
+// qos
+ { "qos_enable", V_01 },
+ { "qos_ack", V_01 },
+ { "qos_syn", V_01 },
+ { "qos_fin", V_01 },
+ { "qos_rst", V_01 },
+ { "qos_icmp", V_01 },
+ { "qos_reset", V_01 },
+ { "qos_obw", V_RANGE(10, 999999) },
+ { "qos_ibw", V_RANGE(10, 999999) },
+ { "qos_orules", V_LENGTH(0, 4096) },
+ { "qos_default", V_RANGE(0, 9) },
+ { "qos_irates", V_LENGTH(0, 128) },
+ { "qos_orates", V_LENGTH(0, 128) },
+
+ { "ne_vegas", V_01 },
+ { "ne_valpha", V_NUM },
+ { "ne_vbeta", V_NUM },
+ { "ne_vgamma", V_NUM },
+
+
+/*
+ppp_static 0/1
+ppp_static_ip IP
+wl_enable 0/1
+wl_wds_timeout
+wl_maxassoc 1-256
+wl_phytype a,b,g
+wl_net_reauth
+wl_preauth
+wl_wme_ap_bk
+wl_wme_ap_be
+wl_wme_ap_vi
+wl_wme_ap_vo
+wl_wme_sta_bk
+wl_wme_sta_be
+wl_wme_sta_vi
+wl_wme_sta_vo
+QoS
+port_priority_1 0-2
+port_flow_control_1 0,1
+port_rate_limit_1 0-8
+port_priority_2 0-2
+port_flow_control_2 0,1
+port_rate_limit_2 0-8
+port_priority_3 0-2
+port_flow_control_3 0,1
+port_rate_limit_3 0-8
+port_priority_4 0-2
+port_flow_control_4 0,1
+port_rate_limit_4 0-8
+wl_ap_ip
+wl_ap_ssid
+*/
+
+ { NULL }
+};
+
+static int save_variables(int write)
+{
+ const nvset_t *v;
+ char *p, *e;
+ int n;
+ long l;
+ unsigned u[6];
+ int ok;
+ char s[256];
+ int dirty;
+ static const char *msgf = "The field \"%s\" is invalid. Please report this problem.";
+
+ dirty = 0;
+ for (v = nvset_list; v->name; ++v) {
+// _dprintf("[%s] %p\n", v->name, webcgi_get((char*)v->name));
+ if ((p = webcgi_get((char*)v->name)) == NULL) continue;
+ ok = 1;
+ switch (v->vtype) {
+ case VT_TEXT:
+ p = unix_string(p); // NOTE: p = malloc'd
+ // drop
+ case VT_LENGTH:
+ n = strlen(p);
+ if ((n < v->va.i) || (n > v->vb.i)) ok = 0;
+ break;
+ case VT_RANGE:
+ l = strtol(p, &e, 10);
+ if ((p == e) || (*e) || (l < v->va.l) || (l > v->vb.l)) ok = 0;
+ break;
+ case VT_IP:
+ if ((sscanf(p, "%3u.%3u.%3u.%3u", &u[0], &u[1], &u[2], &u[3]) != 4) ||
+ (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255)) ok = 0;
+ break;
+ case VT_MAC:
+ if ((sscanf(p, "%2x:%2x:%2x:%2x:%2x:%2x", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]) != 6) ||
+ (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255) || (u[4] > 255) || (u[5] > 255)) ok = 0;
+ break;
+ default:
+ // shutup gcc
+ break;
+ }
+ if (!ok) {
+ if (v->vtype == VT_TEXT) free(p);
+
+ sprintf(s, msgf, v->name);
+ resmsg_set(s);
+ return 0;
+ }
+ if (write) {
+ if (!nvram_match((char *)v->name, p)) {
+ if (v->vtype != VT_TEMP) dirty = 1;
+ nvram_set(v->name, p);
+ }
+ }
+ if (v->vtype == VT_TEXT) free(p);
+ }
+
+
+ // special cases
+
+ char *p1, *p2;
+ if (((p1 = webcgi_get("set_password_1")) != NULL) && (strcmp(p1, "**********") != 0)) {
+ if (((p2 = webcgi_get("set_password_2")) != NULL) && (strcmp(p1, p2) == 0)) {
+ if ((write) && (!nvram_match("http_passwd", p1))) {
+ dirty = 1;
+ nvram_set("http_passwd", p1);
+ }
+ }
+ else {
+ sprintf(s, msgf, "password");
+ resmsg_set(s);
+ return 0;
+ }
+ }
+
+ for (n = 0; n < 50; ++n) {
+ sprintf(s, "rrule%d", n);
+ if ((p = webcgi_get(s)) != NULL) {
+ if (strlen(p) > 2048) {
+ sprintf(s, msgf, s);
+ resmsg_set(s);
+ return 0;
+ }
+ if ((write) && (!nvram_match(s, p))) {
+ dirty = 1;
+ nvram_set(s, p);
+ }
+ }
+ }
+
+ return (write) ? dirty : 1;
+}
+
+static void wo_tomato(char *url)
+{
+ char *v;
+ int i;
+ int ajax;
+ int nvset;
+ const char *red;
+ int commit;
+
+// _dprintf("tomato.cgi\n");
+
+ red = webcgi_safeget("_redirect", "");
+ if (!*red) send_header(200, NULL, mime_html, 0);
+
+ commit = atoi(webcgi_safeget("_commit", "1"));
+ ajax = atoi(webcgi_safeget("_ajax", "0"));
+
+ nvset = atoi(webcgi_safeget("_nvset", "1"));
+ if (nvset) {
+ if (!save_variables(0)) {
+ if (ajax) {
+ web_printf("@msg:%s", resmsg_get());
+ }
+ else {
+ parse_asp("error.asp");
+ }
+ return;
+ }
+ commit = save_variables(1) && commit;
+
+ resmsg_set("Settings saved.");
+ }
+
+ rboot = atoi(webcgi_safeget("_reboot", "0"));
+ if (rboot) {
+ parse_asp("reboot.asp");
+ }
+ else {
+ if (ajax) {
+ web_printf("@msg:%s", resmsg_get());
+ }
+ else if (atoi(webcgi_safeget("_moveip", "0"))) {
+ parse_asp("saved-moved.asp");
+ }
+ else if (!*red) {
+ parse_asp("saved.asp");
+ }
+ }
+
+ if (commit) {
+ _dprintf("commit from tomato.cgi\n");
+ nvram_commit_x();
+ }
+
+ if ((v = webcgi_get("_service")) != NULL) {
+ if (!*red) {
+ if (ajax) web_printf(" Some services are being restarted...");
+ web_close();
+ }
+ sleep(1);
+
+ if (*v == '*') {
+ kill(1, SIGHUP);
+ }
+ else if (*v != 0) {
+ exec_service(v);
+ }
+ }
+
+ for (i = atoi(webcgi_safeget("_sleep", "0")); i > 0; --i) sleep(1);
+
+ if (*red) redirect(red);
+
+ if (rboot) {
+ web_close();
+ sleep(1);
+ kill(1, SIGTERM);
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+
+
+static void wo_update(char *url)
+{
+ const aspapi_t *api;
+ const char *name;
+ int argc;
+ char *argv[16];
+ char s[32];
+
+ if ((name = webcgi_get("exec")) != NULL) {
+ for (api = aspapi; api->name; ++api) {
+ if (strcmp(api->name, name) == 0) {
+ for (argc = 0; argc < 16; ++argc) {
+ sprintf(s, "arg%d", argc);
+ if ((argv[argc] = (char *)webcgi_get(s)) == NULL) break;
+ }
+ api->exec(argc, argv);
+ break;
+ }
+ }
+ }
+}
+
+static void wo_service(char *url)
+{
+ int n;
+
+ exec_service(webcgi_safeget("_service", ""));
+
+ if ((n = atoi(webcgi_safeget("_sleep", "2"))) <= 0) n = 2;
+ sleep(n);
+
+ common_redirect();
+}
+
+static void wo_shutdown(char *url)
+{
+ parse_asp("shutdown.asp");
+ web_close();
+ sleep(1);
+
+ kill(1, SIGQUIT);
+}
+
+static void wo_nvcommit(char *url)
+{
+ parse_asp("saved.asp");
+ web_close();
+ nvram_commit();
+}
+
+
diff --git a/release/src/router/httpd/tomato.h b/release/src/router/httpd/tomato.h
new file mode 100644
index 00000000..3cd6c49b
--- /dev/null
+++ b/release/src/router/httpd/tomato.h
@@ -0,0 +1,162 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#ifndef __TOMATO_H_
+#define __TOMATO_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <typedefs.h>
+#include <syslog.h>
+#include <signal.h>
+
+#include <bcmutils.h>
+#include <bcmnvram.h>
+#include <utils.h>
+#include <shutils.h>
+#include <shared.h>
+
+#include <tomato_profile.h>
+#include <tomato_config.h>
+
+
+#include "httpd.h"
+
+
+#define USE_MINIUPNPD
+// #define BLACKHOLE // for testing
+
+
+#define _dprintf(args...) do { } while(0)
+// #define _dprintf cprintf
+
+extern int rboot;
+
+extern void exec_service(const char *action);
+extern void wi_generic(char *url, int len, char *boundary);
+extern void common_redirect(void);
+
+extern const char *resmsg_get(void);
+extern void resmsg_set(const char *msg);
+extern int resmsg_fread(const char *fname);
+
+
+
+// nvram.c
+extern void asp_nvram(int argc, char **argv);
+extern void asp_nvramseq(int argc, char **argv);
+extern void asp_nv(int argc, char **argv);
+
+// misc.c
+extern char *js_string(const char *s);
+extern char *html_string(const char *s);
+extern char *unix_string(const char *s);
+extern char *reltime(char *buf, time_t t);
+extern int get_client_info(char *mac, char *ifname);
+
+extern void asp_lipp(int argc, char **argv);
+extern void asp_activeroutes(int argc, char **argv);
+extern void asp_cgi_get(int argc, char **argv);
+extern void asp_time(int argc, char **argv);
+extern void asp_wanup(int argc, char **argv);
+extern void asp_wanstatus(int argc, char **argv);
+extern void asp_link_uptime(int argc, char **argv);
+extern void asp_rrule(int argc, char **argv);
+extern void asp_compmac(int argc, char **argv);
+extern void asp_ident(int argc, char **argv);
+extern void asp_lanip(int argc, char **argv);
+extern void asp_psup(int argc, char **argv);
+extern void asp_sysinfo(int argc, char **argv);
+extern void asp_statfs(int argc, char **argv);
+extern void asp_notice(int argc, char **argv);
+extern void wo_wakeup(char *url);
+extern void asp_dns(int argc, char **argv);
+extern void wo_resolve(char *url);
+
+// devlist.c
+extern void asp_arplist(int argc, char **argv);
+extern void asp_devlist(int argc, char **argv);
+
+// ctnf.c
+extern void asp_ctcount(int argc, char **argv);
+extern void asp_ctdump(int argc, char **argv);
+extern void asp_qrate(int argc, char **argv);
+extern void asp_layer7(int argc, char **argv);
+extern void wo_expct(char *url);
+
+// wl.c
+extern void asp_wlscan(int argc, char **argv);
+extern void asp_wlradio(int argc, char **argv);
+extern void wo_wlradio(char *url);
+extern void asp_wlnoise(int argc, char **argv);
+extern void asp_wlcrssi(int argc, char **argv);
+extern void wo_wlmnoise(char *url);
+extern void asp_wlclient(int argc, char **argv);
+extern void asp_wlchannel(int argc, char **argv);
+
+// dhcp.c
+extern void asp_dhcpc_time(int argc, char **argv);
+extern void wo_dhcpd(char *url);
+extern void wo_dhcpc(char *url);
+
+// version.c
+extern void asp_build_time(int argc, char **argv);
+extern void asp_version(int argc, char **argv);
+
+// traceping.c
+extern void wo_trace(char *url);
+extern void wo_ping(char *url);
+
+// log.c
+extern void wo_viewlog(char *url);
+extern void wo_syslog(char *url);
+
+// ddns.c
+extern void asp_ddnsx(int argc, char **argv);
+extern void asp_ddnsx_ip(int argc, char **argv);
+extern void asp_ddnsx_msg(int argc, char **argv);
+
+// upgrade.c
+extern void prepare_upgrade(void);
+extern void wi_upgrade(char *url, int len, char *boundary);
+extern void wo_flash(char *url);
+
+// config.c
+extern void wo_backup(char *url);
+extern void wi_restore(char *url, int len, char *boundary);
+extern void wo_restore(char *url);
+extern void wo_defaults(char *url);
+
+// parser.c
+extern void wo_asp(char *path);
+
+// blackhole.c
+extern void wi_blackhole(char *url, int len, char *boundary);
+
+// upnp.c
+extern void asp_upnpinfo(int argc, char **argv);
+extern void wo_upnp(char *url);
+
+// bwm.c
+extern void wo_bwmbackup(char *url);
+extern void wi_bwmrestore(char *url, int len, char *boundary);
+extern void wo_bwmrestore(char *url);
+extern void asp_netdev(int argc, char **argv);
+extern void asp_bandwidth(int argc, char **argv);
+
+
+#if TOMATO_SL
+// share.c
+extern void asp_sharelist(int argc, char **argv);
+extern void wo_umount(char *url);
+extern void wo_usb(char *url);
+#endif
+
+
+#endif
diff --git a/release/src/router/httpd/traceping.c b/release/src/router/httpd/traceping.c
new file mode 100644
index 00000000..eaf7118c
--- /dev/null
+++ b/release/src/router/httpd/traceping.c
@@ -0,0 +1,108 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <ctype.h>
+
+
+static int check_addr(const char *addr, int max)
+{
+ const char *p;
+ char c;
+
+ if ((addr == NULL) || (addr[0] == 0)) return 0;
+ p = addr;
+ while (*p) {
+ c = *p;
+ if ((!isalnum(c)) && (c != '.') && (c != '-')) return 0;
+ ++p;
+ }
+ return((p - addr) <= max);
+}
+
+void wo_trace(char *url)
+{
+ char cmd[256];
+ const char *addr;
+
+ addr = webcgi_get("addr");
+ if (!check_addr(addr, 64)) return;
+
+ killall("traceroute", SIGTERM);
+
+ web_puts("\ntracedata = '");
+ sprintf(cmd, "traceroute -I -m %u -w %u %s", atoi(webcgi_safeget("hops", "0")), atoi(webcgi_safeget("wait", "0")), addr);
+ web_pipecmd(cmd, WOF_JAVASCRIPT);
+ web_puts("';");
+}
+
+void wo_ping(char *url)
+{
+ char cmd[256];
+ const char *addr;
+
+ addr = webcgi_get("addr");
+ if (!check_addr(addr, 64)) return;
+
+ killall("ping", SIGTERM);
+
+ web_puts("\npingdata = '");
+ sprintf(cmd, "ping -c %d -s %d %s", atoi(webcgi_safeget("count", "0")), atoi(webcgi_safeget("size", "0")), addr);
+ web_pipecmd(cmd, WOF_JAVASCRIPT);
+ web_puts("';");
+}
+
+
+/*
+#include <regex.h>
+
+int main(int argc, char **argv)
+{
+ FILE *f;
+ char s[1024];
+ int n;
+ char domain[512];
+ char ip[32];
+ char min[32];
+ regex_t re;
+ regmatch_t rm[10];
+ int i;
+
+ if ((f = popen("traceroute -I 192.168.0.1", "r")) == NULL) {
+ perror("popen");
+ return 1;
+ }
+// 2 192.168.0.1 (192.168.0.1) 1.908 ms 1.812 ms 1.688 ms
+
+ while (fgets(s, sizeof(s), f)) {
+
+ //
+ if (regcomp(&re, "^ +[0-9]+ +(.+?) +\\((.+?)\\) +(.+?) ms +(.+?) ms +(.+?) ms", REG_EXTENDED) != 0) {
+ printf("error: regcomp\n");
+ return 1;
+ }
+ if ((regexec(&re, s, sizeof(rm) / sizeof(rm[0]), rm, 0) == 0) && (re.re_nsub == 5)) {
+ printf("[");
+ for (i = 1; i < 6; ++i) {
+ s[rm[i].rm_eo] = 0;
+ printf("'%s'%c", s + rm[i].rm_so, (i == 5) ? ' ' : ',');
+ }
+ printf("]\n");
+// printf("%d = %d = [%s]\n", i, rm[i].rm_so, s + rm[i].rm_so);
+ }
+ regfree(&re);
+
+// sscanf(s, "%d %s (%s) %s ms", &n, domain, ip, min);
+// printf("[%s] %s %s\n", ip, domain, min);
+ }
+ pclose(f);
+
+ return 0;
+}
+
+*/
diff --git a/release/src/router/httpd/upgrade.c b/release/src/router/httpd/upgrade.c
new file mode 100644
index 00000000..ce3e27c4
--- /dev/null
+++ b/release/src/router/httpd/upgrade.c
@@ -0,0 +1,153 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/wait.h>
+#include <typedefs.h>
+#include <sys/reboot.h>
+
+#if 1
+#define MTD_WRITE_CMD "mtd-write"
+#else
+#define DEBUG_TEST
+#define MTD_WRITE_CMD "/tmp/mtd-write"
+#endif
+
+void prepare_upgrade(void)
+{
+ int n;
+
+ // stop non-essential stuff & free up some memory
+ exec_service("upgrade-start");
+ for (n = 30; n > 0; --n) {
+ sleep(1);
+ if (nvram_match("action_service", "")) break; // this is cleared at the end
+ }
+ unlink("/var/log/messages");
+ unlink("/var/log/messages.0");
+ sync();
+}
+
+void wi_upgrade(char *url, int len, char *boundary)
+{
+ uint8 buf[1024];
+ const char *error = "Error reading file";
+ int ok = 0;
+ int n;
+
+ check_id(url);
+
+ // quickly check if JFFS2 is mounted by checking if /jffs/ is not squashfs
+ struct statfs sf;
+ if ((statfs("/jffs", &sf) != 0) || (sf.f_type != 0x73717368)) {
+ error = "JFFS2 is currently in use. Since an upgrade may overwrite the "
+ "JFFS2 partition, please backup the contents, disable JFFS2, then reboot the router";
+ goto ERROR;
+ }
+
+ // skip the rest of the header
+ if (!skip_header(&len)) goto ERROR;
+
+ if (len < (1 * 1024 * 1024)) {
+ error = "Invalid file";
+ goto ERROR;
+ }
+
+ // -- anything after here ends in a reboot --
+
+ rboot = 1;
+
+ led(LED_DIAG, 1);
+
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+
+ prepare_upgrade();
+ system("cp reboot.asp /tmp"); // copy to memory
+
+ char fifo[] = "/tmp/flashXXXXXX";
+ int pid = -1;
+ FILE *f = NULL;
+
+ if ((mktemp(fifo) == NULL) ||
+ (mkfifo(fifo, S_IRWXU) < 0)) {
+ error = "Unable to create a fifo";
+ goto ERROR2;
+ }
+
+ char *wargv[] = { MTD_WRITE_CMD, "-w", "-i", fifo, "-d", "linux", NULL };
+ if (_eval(wargv, ">/tmp/.mtd-write", 0, &pid) != 0) {
+ error = "Unable to start flash program";
+ goto ERROR2;
+ }
+
+ if ((f = fopen(fifo, "w")) == NULL) {
+ error = "Unable to start pipe for mtd write";
+ goto ERROR2;
+ }
+
+ // !!! This will actually write the boundary. But since mtd-write
+ // uses trx length... -- zzz
+
+ while (len > 0) {
+ if ((n = web_read(buf, MIN(len, sizeof(buf)))) <= 0) {
+ goto ERROR2;
+ }
+ len -= n;
+ if (safe_fwrite(buf, 1, n, f) != n) {
+ error = "Error writing to pipe";
+ goto ERROR2;
+ }
+ }
+
+ error = NULL;
+ ok = 1;
+
+ERROR2:
+ rboot = 1;
+ set_action(ACT_REBOOT);
+
+ if (f) fclose(f);
+ if (pid != -1) waitpid(pid, &n, 0);
+
+ resmsg_fread("/tmp/.mtd-write");
+
+ web_eat(len);
+ return;
+
+ERROR:
+ resmsg_set(error);
+ web_eat(len);
+}
+
+void wo_flash(char *url)
+{
+ if (rboot) {
+ parse_asp("/tmp/reboot.asp");
+ web_close();
+
+#ifdef DEBUG_TEST
+ printf("\n\n -- reboot -- \n\n");
+ set_action(ACT_IDLE);
+#else
+ killall("pppoecd", SIGTERM);
+ sleep(2);
+ // kill(1, SIGTERM);
+ reboot(RB_AUTOBOOT);
+#endif
+ exit(0);
+ }
+
+ parse_asp("error.asp");
+}
diff --git a/release/src/router/httpd/upnp.c b/release/src/router/httpd/upnp.c
new file mode 100644
index 00000000..8a8f8fe0
--- /dev/null
+++ b/release/src/router/httpd/upnp.c
@@ -0,0 +1,74 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+void asp_upnpinfo(int argc, char **argv)
+{
+#ifdef USE_MINIUPNPD
+ if (nvram_get_int("upnp_enable")) {
+ f_write_string("/etc/upnp/info", "", 0, 0);
+ if (killall("miniupnpd", SIGUSR2) == 0) {
+ f_wait_notexists("/etc/upnp/info", 5);
+ }
+
+ web_puts("\nmupnp_data = '");
+ web_putfile("/etc/upnp/data.info", WOF_JAVASCRIPT);
+ web_puts("';\n");
+ }
+#else
+ unlink("/var/spool/upnp.js");
+ if (nvram_get_int("upnp_enable") == 1) {
+ if (killall("upnp", SIGUSR2) == 0) {
+ f_wait_exists("/var/spool/upnp.js", 5);
+ }
+ }
+
+ web_puts("\nupnp_data = [\n");
+ do_file("/var/spool/upnp.js");
+ web_puts("];\n");
+ unlink("/var/spool/upnp.js");
+#endif
+}
+
+void wo_upnp(char *url)
+{
+#ifdef USE_MINIUPNPD
+ char s[256];
+ const char *proto;
+ const char *eport;
+
+ if (nvram_get_int("upnp_enable")) {
+ if (((proto = webcgi_get("remove_proto")) != NULL) && (*proto) &&
+ ((eport = webcgi_get("remove_eport")) != NULL) && (*eport)) {
+ sprintf(s, "%3s %6s\n", proto, eport);
+ f_write_string("/etc/upnp/delete", s, 0, 0);
+ if (killall("miniupnpd", SIGUSR2) == 0) {
+ f_wait_notexists("/etc/upnp/delete", 5);
+ }
+ }
+ }
+ common_redirect();
+#else
+ char s[256];
+ const char *proto;
+ const char *port;
+
+ if (nvram_get_int("upnp_enable") == 1) {
+ if (((proto = webcgi_get("remove_proto")) != NULL) && (*proto) &&
+ ((port = webcgi_get("remove_ext_port")) != NULL) && (*port)) {
+
+ sprintf(s, "%s %s\n", proto, port);
+ f_write_string("/var/spool/upnp.delete", s, 0, 0);
+ if (killall("upnp", SIGUSR2) == 0) {
+ f_wait_notexists("/var/spool/upnp.delete", 5);
+ }
+ }
+ }
+ common_redirect();
+#endif
+}
diff --git a/release/src/router/httpd/version.c b/release/src/router/httpd/version.c
new file mode 100644
index 00000000..bdd1a5d2
--- /dev/null
+++ b/release/src/router/httpd/version.c
@@ -0,0 +1,24 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+void asp_build_time(int argc, char **argv)
+{
+ web_puts(tomato_buildtime);
+}
+
+void asp_version(int argc, char **argv)
+{
+ if (argc != 0) {
+ web_puts(tomato_version);
+ }
+ else {
+ web_write(tomato_version, strrchr(tomato_version, '.') - tomato_version);
+ }
+}
+
diff --git a/release/src/router/httpd/webio.c b/release/src/router/httpd/webio.c
new file mode 100644
index 00000000..11e8a67a
--- /dev/null
+++ b/release/src/router/httpd/webio.c
@@ -0,0 +1,229 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+#include "tomato.h"
+
+#include "../mssl/mssl.h"
+extern int do_ssl;
+
+#include <errno.h>
+#include <stdarg.h>
+
+extern FILE *connfp;
+extern int connfd;
+
+int web_getline(char *buffer, int max)
+{
+ while (fgets(buffer, max, connfp) == NULL) {
+ if (errno != EINTR) return 0;
+ }
+// cprintf("%s", buffer);
+ return 1;
+}
+
+void web_puts(const char *buffer)
+{
+ web_write(buffer, strlen(buffer));
+}
+
+void web_putj(const char *buffer)
+{
+ char *p;
+
+ p = js_string(buffer);
+ if (p) {
+ web_puts(p);
+ free(p);
+ }
+}
+
+void web_puth(const char *buffer)
+{
+ char *p;
+
+ p = html_string(buffer);
+ if (p) {
+ web_puts(p);
+ free(p);
+ }
+}
+
+int _web_printf(wofilter_t wof, const char *format, ...)
+{
+ va_list args;
+ char *b, *p;
+ int size;
+ int n;
+
+ size = 1024;
+ while (1) {
+ if ((b = malloc(size)) == NULL) return 0;
+
+ va_start(args, format);
+ n = vsnprintf(b, size, format, args);
+ va_end(args);
+
+ if (n > -1) {
+ if (n < size) {
+ switch (wof) {
+ case WOF_JAVASCRIPT:
+ p = js_string(b);
+ free(b);
+ break;
+ case WOF_HTML:
+ p = html_string(b);
+ free(b);
+ break;
+ default:
+ p = b;
+ break;
+ }
+ if (!p) return 0;
+ web_puts(p);
+ free(p);
+ return 1;
+ }
+ size = n + 1;
+ }
+ else size *= 2;
+
+ free(b);
+ if (size > (10 * 1024)) return 0;
+ }
+}
+
+int web_write(const char *buffer, int len)
+{
+ int n = len;
+ int r = 0;
+
+ while (n > 0) {
+ r = fwrite(buffer, 1, n, connfp);
+ if ((r == 0) && (errno != EINTR)) return -1;
+ buffer += r;
+ n -= r;
+ }
+ return r;
+}
+
+int web_read(void *buffer, int len)
+{
+ int r;
+ if (len <= 0) return 0;
+ while ((r = fread(buffer, 1, len, connfp)) == 0) {
+ if (errno != EINTR) return -1;
+ }
+ return r;
+}
+
+int web_read_x(void *buffer, int len)
+{
+ int n;
+ int t = 0;
+ while (len > 0) {
+ n = web_read(buffer, len);
+ if (n <= 0) return len;
+ (unsigned char *)buffer += n;
+ len -= n;
+ t += n;
+ }
+ return t;
+}
+
+int web_eat(int max)
+{
+ char buf[512];
+ int n;
+ while (max > 0) {
+ if ((n = web_read(buf, (max < sizeof(buf)) ? max : sizeof(buf))) <= 0) return 0;
+ max -= n;
+ }
+ return 1;
+}
+
+int web_flush(void)
+{
+ return (fflush(connfp) == 0);
+}
+
+int web_open(void)
+{
+ if (do_ssl) {
+#ifdef TCONFIG_HTTPS
+ if ((connfp = ssl_server_fopen(connfd)) != NULL) return 1;
+#endif
+ }
+ else {
+ if ((connfp = fdopen(connfd, "r+")) != NULL) return 1;
+ }
+ return 0;
+}
+
+int web_close(void)
+{
+ if (connfp != NULL) {
+ fflush(connfp);
+ fclose(connfp);
+ connfp = NULL;
+ }
+ if (connfd != -1) {
+// shutdown(connfd, SHUT_RDWR);
+ close(connfd);
+ connfd = -1;
+ }
+ return 1;
+}
+
+
+// --------------------------------------------------------------------------------------------------------------------
+
+
+static void _web_putfile(FILE *f, wofilter_t wof)
+{
+ char buf[2048];
+ int nr;
+
+ while ((nr = fread(buf, 1, sizeof(buf) - 1, f)) > 0) {
+ buf[nr] = 0;
+ switch (wof) {
+ case WOF_JAVASCRIPT:
+ web_putj(buf);
+ break;
+ case WOF_HTML:
+ web_puth(buf);
+ break;
+ default:
+ web_puts(buf);
+ break;
+ }
+ }
+}
+
+int web_putfile(const char *fname, wofilter_t wof)
+{
+ FILE *f;
+
+ if ((f = fopen(fname, "r")) != NULL) {
+ _web_putfile(f, wof);
+ fclose(f);
+ return 1;
+ }
+ return 0;
+}
+
+int web_pipecmd(const char *cmd, wofilter_t wof)
+{
+ FILE *f;
+
+ if ((f = popen(cmd, "r")) != NULL) {
+ _web_putfile(f, wof);
+ pclose(f);
+ return 1;
+ }
+ return 0;
+}
+
+
diff --git a/release/src/router/httpd/webmsg.c b/release/src/router/httpd/webmsg.c
new file mode 100644
index 00000000..50448567
--- /dev/null
+++ b/release/src/router/httpd/webmsg.c
@@ -0,0 +1,65 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <sys/stat.h>
+
+
+
+static const char webMsgFile[] = "/tmp/.webmsg";
+
+
+void setWebMsg(const char *s)
+{
+ FILE *f;
+ if (s) {
+ if ((f = fopen(webMsgFile, "w")) != NULL) {
+ fputs(s, f);
+ fclose(f);
+ }
+ }
+ else {
+ unlink(webMsgFile);
+ }
+}
+
+void getWebMsg(char *s, int max)
+{
+ FILE *f;
+ int n;
+
+ if ((f = fopen(webMsgFile, "r")) != NULL) {
+ n = fread(s, 1, max - 1, f);
+ s[n] = 0;
+ fclose(f);
+ unlink(webMsgFile);
+ }
+ else s[0] = 0;
+}
+
+int webMsgExist(void)
+{
+ struct stat st;
+ return ((stat(webMsgFile, &st) == 0) && (st.st_size > 0));
+}
+
+void asp_webmsg(int argc, char **argv)
+{
+ char s[512];
+ const char *msg = s;
+
+ getWebMsg(s, sizeof(s));
+ if (s[0] == 0) {
+ if (argc == 0) return;
+ msg = argv[0];
+ }
+ if ((argc >= 2) && (argv[1][0] == '1')) web_putj(msg);
+ else web_puth(msg);
+}
+
+
diff --git a/release/src/router/httpd/wl.c b/release/src/router/httpd/wl.c
new file mode 100644
index 00000000..5d4fc1d9
--- /dev/null
+++ b/release/src/router/httpd/wl.c
@@ -0,0 +1,247 @@
+/*
+
+ Tomato Firmware
+ Copyright (C) 2006-2009 Jonathan Zarate
+
+*/
+
+#include "tomato.h"
+
+#include <ctype.h>
+#include <wlutils.h>
+
+
+// returns: ['bssid','ssid',channel,capabilities,rssi,noise,[rates,]], or [null,'error message']
+void asp_wlscan(int argc, char **argv)
+{
+ // scan
+
+ wl_scan_params_t sp;
+ int ap;
+ int radio;
+ char *wif;
+ int zero = 0;
+
+ web_puts("\nwlscandata = [");
+
+ wif = nvram_safe_get("wl_ifname");
+
+ memset(&sp, 0xff, sizeof(sp)); // most default to -1
+ sp.ssid.SSID_len = 0;
+ sp.bss_type = DOT11_BSSTYPE_ANY; // =2
+ sp.channel_num = 0;
+
+ if (wl_ioctl(wif, WLC_GET_AP, &ap, sizeof(ap)) < 0) {
+ web_puts("[null,'Unable to get AP mode.']];\n");
+ return;
+ }
+ if (ap > 0) {
+ wl_ioctl(wif, WLC_SET_AP, &zero, sizeof(zero));
+ }
+
+ radio = get_radio();
+ if (!radio) set_radio(1);
+
+ if (wl_ioctl(wif, WLC_SCAN, &sp, WL_SCAN_PARAMS_FIXED_SIZE) < 0) {
+ if (ap > 0) wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap));
+ if (!radio) set_radio(0);
+ web_puts("[null,'Unable to start scan.']];\n");
+ return;
+ }
+
+ sleep(2);
+
+
+ // get results
+
+ wl_scan_results_t *results;
+ wl_bss_info_t *bssi;
+ int r;
+
+ results = malloc(WLC_IOCTL_MAXLEN);
+ if (!results) {
+ if (ap > 0) wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap));
+ if (!radio) set_radio(0);
+ web_puts("[null,'Not enough memory.']];");
+ return;
+ }
+ results->buflen = WLC_IOCTL_MAXLEN - (sizeof(*results) - sizeof(results->bss_info));
+ results->version = WL_BSS_INFO_VERSION;
+ r = wl_ioctl(wif, WLC_SCAN_RESULTS, results, WLC_IOCTL_MAXLEN);
+
+ if (ap > 0) {
+ wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap));
+#ifndef WL_BSS_INFO_VERSION
+#error WL_BSS_INFO_VERSION
+#endif
+
+#if WL_BSS_INFO_VERSION >= 108
+ // no idea why this voodoo sequence works to wake up wl -- zzz
+ eval("wl", "ssid", nvram_safe_get("wl_ssid"));
+ if (radio) set_radio(1);
+#endif
+ }
+ if (!radio) set_radio(0);
+
+ if (r < 0) {
+ free(results);
+ web_puts("[null,'Unable to obtain scan result.']];\n");
+ return;
+ }
+
+
+ // format for javascript
+
+ int i;
+ int j;
+ int k;
+ char c;
+ char ssid[64];
+ char mac[32];
+ char *ssidj;
+ int channel;
+
+ bssi = &results->bss_info[0];
+ for (i = 0; i < results->count; ++i) {
+
+#if WL_BSS_INFO_VERSION >= 108
+ channel = CHSPEC_CHANNEL(bssi->chanspec);
+#else
+ channel = bssi->channel;
+#endif
+
+ j = bssi->SSID_len;
+ if (j < 0) j = 0;
+ if (j > 32) j = 32;
+ if (nvram_get_int("wlx_scrubssid")) {
+ for (k = j - 1; k >= 0; --k) {
+ c = bssi->SSID[k];
+ if (!isprint(c)) c = '?';
+ ssid[k] = c;
+ }
+ }
+ else {
+ memcpy(ssid, bssi->SSID, j);
+ }
+ ssid[j] = 0;
+ ssidj = js_string(ssid);
+
+ web_printf("%s['%s','%s',%u,%u,%d,%d,[", (i > 0) ? "," : "",
+ ether_etoa(bssi->BSSID.octet, mac), ssidj ? ssidj : "",
+ channel,
+ bssi->capability, bssi->RSSI, bssi->phy_noise);
+ free(ssidj);
+
+ for (j = 0; j < bssi->rateset.count; ++j) {
+ web_printf("%s%u", j ? "," : "", bssi->rateset.rates[j]);
+ }
+ web_puts("]]");
+
+ bssi = (wl_bss_info_t*)((uint8*)bssi + bssi->length);
+ }
+
+ web_puts("];\n");
+ free(results);
+}
+
+
+void asp_wlradio(int argc, char **argv)
+{
+ web_printf("\nwlradio = %d;\n", get_radio());
+}
+
+void wo_wlradio(char *url)
+{
+ char *enable;
+
+ parse_asp("saved.asp");
+ if (nvram_match("wl_radio", "1")) {
+ if ((enable = webcgi_get("enable")) != NULL) {
+ web_close();
+ sleep(2);
+ eval("radio", atoi(enable) ? "on" : "off");
+ return;
+ }
+ }
+}
+
+static int read_noise(void)
+{
+ int v;
+
+ // WLC_GET_PHY_NOISE
+ if (wl_ioctl(nvram_safe_get("wl_ifname"), 135, &v, sizeof(v)) == 0) {
+ char s[32];
+ sprintf(s, "%d", v);
+ nvram_set("t_noise", s);
+ return v;
+ }
+ return -99;
+}
+
+void asp_wlcrssi(int argc, char **argv)
+{
+ scb_val_t rssi;
+
+ memset(&rssi, 0, sizeof(rssi));
+ if (wl_client()) {
+ if (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_RSSI, &rssi, sizeof(rssi)) != 0)
+ rssi.val = -100;
+ }
+ web_printf("\nwlcrssi = %d;\n", rssi.val);
+}
+
+void asp_wlnoise(int argc, char **argv)
+{
+ int v;
+
+ if (wl_client()) {
+ v = read_noise();
+ }
+ else {
+ v = nvram_get_int("t_noise");
+ if ((v > 0) || (v < -100)) v = -99;
+ }
+ web_printf("\nwlnoise = %d;\n", v);
+}
+
+void wo_wlmnoise(char *url)
+{
+ int ap;
+ int i;
+ char *wif;
+
+ parse_asp("mnoise.asp");
+ web_close();
+ sleep(3);
+
+ wif = nvram_safe_get("wl_ifname");
+ if (wl_ioctl(wif, WLC_GET_AP, &ap, sizeof(ap)) < 0) return;
+
+ i = 0;
+ wl_ioctl(wif, WLC_SET_AP, &i, sizeof(i));
+
+ for (i = 10; i > 0; --i) {
+ sleep(1);
+ read_noise();
+ }
+
+ wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap));
+}
+
+void asp_wlclient(int argc, char **argv)
+{
+ web_puts(wl_client() ? "1" : "0");
+}
+
+void asp_wlchannel(int argc, char **argv)
+{
+ channel_info_t ch;
+
+ if (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_CHANNEL, &ch, sizeof(ch)) < 0) {
+ web_puts(nvram_safe_get("wl_channel"));
+ }
+ else {
+ web_printf("%d", (ch.scan_channel > 0) ? -ch.scan_channel : ch.hw_channel);
+ }
+}