[hackers] [quark] Add vhost support || Laslo Hunhold

From: <git_AT_suckless.org>
Date: Tue, 11 Jul 2017 12:56:54 +0200 (CEST)

commit 000553d8c5ff70e8eaedab0ba9604270c96eb2e5
Author: Laslo Hunhold <dev_AT_frign.de>
AuthorDate: Tue Jul 11 12:34:55 2017 +0200
Commit: Laslo Hunhold <dev_AT_frign.de>
CommitDate: Tue Jul 11 12:55:39 2017 +0200

    Add vhost support
    
    As given in the config, we match a regex of hosts to a canonical host
    which points to an internal directory.
    Regexes are compiled on initialization, so we can error out early.
    The rest is just modifications to use relative directories rather than
    absolute ones, as we chdir() into the vhost directories dynamically.
    
    Given we normalize the targets beforehand, there is no danger of
    malformed requests escaping the vhost-context.

diff --git a/config.def.h b/config.def.h
index 863add9..563fcb9 100644
--- a/config.def.h
+++ b/config.def.h
_AT_@ -2,15 +2,26 @@ static const char *host = "localhost";
 static const char *port = "80";
 static const char *servedir = ".";
 static const char *docindex = "index.html";
-static int listdirs = 1;
+
 static const char *user = "nobody";
 static const char *group = "nogroup";
+
+static int listdirs = 1;
+static int vhosts = 0;
 static const int maxnprocs = 512;
 
 #define HEADER_MAX 4096
 #define FIELD_MAX 200
 
 static const struct {
+ char *name;
+ char *regex;
+ char *dir;
+} vhost[] = {
+ { "example.org", "^(www.)example.org$", "/example.org" },
+};
+
+static const struct {
         char *ext;
         char *type;
 } mimes[] = {
diff --git a/quark.c b/quark.c
index 67b696a..8bf94ff 100644
--- a/quark.c
+++ b/quark.c
_AT_@ -16,6 +16,7 @@
 #include <limits.h>
 #include <netdb.h>
 #include <pwd.h>
+#include <regex.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
_AT_@ -32,6 +33,10 @@ char *argv0;
 
 #undef MIN
 #define MIN(x,y) ((x) < (y) ? (x) : (y))
+#undef LEN
+#define LEN(x) (sizeof (x) / sizeof *(x))
+#undef RELPATH
+#define RELPATH(x) ((!*(x) || !strcmp(x, "/")) ? "." : ((x) + 1))
 
 #define TIMESTAMP_LEN 30
 
_AT_@ -97,6 +102,9 @@ static char *status_str[] = {
         [S_VERSION_NOT_SUPPORTED] = "HTTP Version not supported",
 };
 
+/* vhost regex compilate */
+static regex_t vhost_regex[LEN(vhost)];
+
 long long strtonum(const char *, long long, long long, const char **);
 
 static char *
_AT_@ -555,6 +563,23 @@ sendresponse(int fd, struct request *r)
         char *p, *q, *mime;
         const char *err;
 
+ /* match vhost */
+ if (vhosts) {
+ for (i = 0; i < LEN(vhost); i++) {
+ if (!regexec(&vhost_regex[i], r->field[REQ_HOST], 0,
+ NULL, 0)) {
+ break;
+ }
+ }
+ if (i < LEN(vhost)) {
+ /* switch to vhost directory */
+ if (chdir(vhost[i].dir) < 0) {
+ return sendstatus(fd, (errno == EACCES) ?
+ S_FORBIDDEN : S_NOT_FOUND);
+ }
+ }
+ }
+
         /* normalize target */
         memcpy(realtarget, r->target, sizeof(realtarget));
         if (normabspath(realtarget)) {
_AT_@ -567,7 +592,7 @@ sendresponse(int fd, struct request *r)
         }
 
         /* stat the target */
- if (stat(realtarget, &st) < 0) {
+ if (stat(RELPATH(realtarget), &st) < 0) {
                 return sendstatus(fd, (errno == EACCES) ? S_FORBIDDEN : S_NOT_FOUND);
         }
 
_AT_@ -583,8 +608,9 @@ sendresponse(int fd, struct request *r)
                 }
         }
 
- /* redirect if targets differ */
- if (strcmp(r->target, realtarget)) {
+ /* redirect if targets differ or host is non-canonical */
+ if (strcmp(r->target, realtarget) || (vhosts && r->field[REQ_HOST][0] &&
+ strcmp(r->field[REQ_HOST], vhost[i].name))) {
                 /* do we need to add a port to the Location? */
                 hasport = strcmp(port, "80");
 
_AT_@ -609,7 +635,8 @@ sendresponse(int fd, struct request *r)
                             S_MOVED_PERMANENTLY,
                             status_str[S_MOVED_PERMANENTLY],
                             timestamp(time(NULL), t), ipv6host ? "[" : "",
- r->field[REQ_HOST][0] ? r->field[REQ_HOST] : host,
+ r->field[REQ_HOST][0] ? (vhosts && i < LEN(vhost)) ?
+ vhost[i].name : r->field[REQ_HOST] : host,
                             ipv6host ? "]" : "", hasport ? ":" : "",
                             hasport ? port : "", tmptarget) < 0) {
                         return S_REQUEST_TIMEOUT;
_AT_@ -626,12 +653,12 @@ sendresponse(int fd, struct request *r)
                 }
 
                 /* stat the docindex, which must be a regular file */
- if (stat(realtarget, &st) < 0 || !S_ISREG(st.st_mode)) {
+ if (stat(RELPATH(realtarget), &st) < 0 || !S_ISREG(st.st_mode)) {
                         if (listdirs) {
                                 /* remove index suffix and serve dir */
                                 realtarget[strlen(realtarget) -
                                            strlen(docindex)] = '\0';
- return senddir(fd, realtarget, r);
+ return senddir(fd, RELPATH(realtarget), r);
                         } else {
                                 /* reject */
                                 if (!S_ISREG(st.st_mode) || errno == EACCES) {
_AT_@ -721,7 +748,7 @@ sendresponse(int fd, struct request *r)
                 }
         }
 
- return sendfile(fd, realtarget, r, &st, mime, lower, upper);
+ return sendfile(fd, RELPATH(realtarget), r, &st, mime, lower, upper);
 }
 
 static void
_AT_@ -782,14 +809,14 @@ serve(int insock)
                                 inet_ntop(AF_INET,
                                           &(((struct sockaddr_in *)&in_sa)->sin_addr),
                                           inip4, sizeof(inip4));
- printf("%s\t%s\t%d\t%s\n", tstmp, inip4,
- status, r.target);
+ printf("%s\t%s\t%d\t%s\t%s\n", tstmp, inip4,
+ status, r.field[REQ_HOST], r.target);
                         } else {
                                 inet_ntop(AF_INET6,
                                           &(((struct sockaddr_in6*)&in_sa)->sin6_addr),
                                           inip6, sizeof(inip6));
- printf("%s\t%s\t%d\t%s\n", tstmp, inip6,
- status, r.target);
+ printf("%s\t%s\t%d\t%s\t%s\n", tstmp, inip6,
+ status, r.field[REQ_HOST], r.target);
                         }
 
                         /* clean up and finish */
_AT_@ -902,7 +929,7 @@ main(int argc, char *argv[])
         struct passwd *pwd = NULL;
         struct group *grp = NULL;
         struct rlimit rlim;
- int insock;
+ int i, insock;
         char *udsname = NULL;
 
         ARGBEGIN {
_AT_@ -941,6 +968,17 @@ main(int argc, char *argv[])
                 usage();
         }
 
+ /* compile and check the supplied vhost regexes */
+ if (vhosts) {
+ for (i = 0; i < LEN(vhost); i++) {
+ if (regcomp(&vhost_regex[i], vhost[i].regex,
+ REG_ICASE | REG_NOSUB)) {
+ die("%s: regcomp '%s': invalid regex\n", argv0,
+ vhost[i].regex);
+ }
+ }
+ }
+
         /* reap children automatically */
         if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
                 fprintf(stderr, "%s: signal: Failed to set SIG_IGN on"
Received on Tue Jul 11 2017 - 12:56:54 CEST

This archive was generated by hypermail 2.3.0 : Tue Jul 11 2017 - 13:01:51 CEST