diff options
Diffstat (limited to 'src/user')
-rw-r--r-- | src/user/app/httpd/httpd.c | 80 | ||||
-rw-r--r-- | src/user/app/netstack/fs.c | 12 |
2 files changed, 89 insertions, 3 deletions
diff --git a/src/user/app/httpd/httpd.c b/src/user/app/httpd/httpd.c new file mode 100644 index 0000000..1aaebc5 --- /dev/null +++ b/src/user/app/httpd/httpd.c @@ -0,0 +1,80 @@ +/* garbage httpd, just to see if it works + * easily DoSable (like the rest of the network stack), vulnerable to path traversal, etc */ +#include <camellia/flags.h> +#include <camellia/syscalls.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#define eprintf(fmt, ...) fprintf(stderr, "httpd: "fmt"\n" __VA_OPT__(,) __VA_ARGS__) + +static void handle(FILE *c) { + char buf[2048]; + fgets(buf, sizeof buf, c); + printf("%s", buf); + + if (memcmp(buf, "GET /", 5) != 0) { + fprintf(c, "HTTP/1.1 400 Bad Request\r\n\r\n"); + return; + } + char *path = buf + 4; + char *end = strchr(path, ' '); + if (end) *end = '\0'; + + handle_t h = _syscall_open(path, strlen(path), OPEN_RO); + if (h < 0) { + fprintf(c, "HTTP/1.1 404 Not Found\r\n\r\n"); + return; + } + FILE *f = fdopen(h, "r"); + if (!f) { + fprintf(c, "HTTP/1.1 500 Internal Server Error\r\n\r\n"); + return; + } + + if (path[strlen(path) - 1] != '/') { + /* regular file */ + fprintf(c, "HTTP/1.1 200 OK\r\n"); + fprintf(c, "\r\n"); + for (;;) { + int len = fread(buf, 1, sizeof buf, f); + if (len <= 0) break; + fwrite(buf, 1, len, c); + } + } else { + /* directory listing */ + fprintf(c, "HTTP/1.1 200 OK\r\n"); + fprintf(c, "Content-Type: text/html; charset=UTF-8\r\n"); + fprintf(c, "\r\n"); + fprintf(c, "<h1>directory listing for %s</h1><hr><ul><li><a href=..>..</a></li>", path); + for (;;) { + int len = fread(buf, 1, sizeof buf, f); + if (len <= 0) break; + // TODO directory library + // based on find.c + for (int pos = 0; pos < len; ) { + if (buf[pos] == '\0') break; + const char *end = memchr(buf + pos, 0, len - pos); + if (!end) break; + fprintf(c, "<li><a href=\"%s\">%s</a></li>", buf + pos, buf + pos); + pos += end - (buf + pos) + 1; + } + } + } + fclose(f); +} + +int main(int argc, char **argv) { + const char *path = (argc > 1) ? argv[1] : "/net/0.0.0.0/listen/tcp/80"; + handle_t conn; + for (;;) { + conn = _syscall_open(path, strlen(path), 0); + if (conn < 0) { + eprintf("open('%s') failed, %d", path, conn); + return 1; + } + FILE *f = fdopen(conn, "a+"); + handle(f); + fclose(f); + } +} diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c index f4d9625..9f40ef8 100644 --- a/src/user/app/netstack/fs.c +++ b/src/user/app/netstack/fs.c @@ -12,6 +12,7 @@ */ #include "proto.h" #include "util.h" +#include <camellia/flags.h> #include <camellia/syscalls.h> #include <errno.h> #include <stdio.h> @@ -58,7 +59,9 @@ static void tcp_recv_callback(void *arg) { struct handle *h = arg; char buf[1024]; if (h->reqh >= 0) { - size_t len = tcpc_tryread(h->tcp.c, buf, sizeof buf); + if (h->tcp.readcap > sizeof buf) + h->tcp.readcap = sizeof buf; + size_t len = tcpc_tryread(h->tcp.c, buf, h->tcp.readcap); if (len > 0) { _syscall_fs_respond(h->reqh, buf, len, 0); h->reqh = -1; @@ -122,7 +125,7 @@ static void recv_enqueue(struct handle *h, handle_t reqh, size_t readcap) { } } -static void fs_open(handle_t reqh, char *path) { +static void fs_open(handle_t reqh, char *path, int flags) { #define respond(buf, val) do{ _syscall_fs_respond(reqh, buf, val, 0); return; }while(0) struct handle *h; if (*path != '/') respond(NULL, -1); @@ -140,6 +143,9 @@ static void fs_open(handle_t reqh, char *path) { respond(h, 0); } + /* everything below ends up sending packets */ + if (flags & OPEN_RO) respond(NULL, -EACCES); + char *save; const char *verb, *proto, *port_s; @@ -241,7 +247,7 @@ void fs_thread(void *arg) { (void)arg; case VFSOP_OPEN: if (res.len < buflen) { buf[res.len] = '\0'; - fs_open(reqh, buf); + fs_open(reqh, buf, res.flags); } else { _syscall_fs_respond(reqh, NULL, -1, 0); } |