From 448281ee99f74759d7f35d10969db21b04c42389 Mon Sep 17 00:00:00 2001 From: Nishi Date: Fri, 13 Sep 2024 13:36:03 +0000 Subject: [PATCH] vhost works git-svn-id: file:///raid/svn-personal/tewi/trunk@12 8739d7e6-ffea-ec47-b151-bdff447c6205 --- Common/log.c | 3 ++- Server/config.c | 54 +++++++++++++++++++++++++++++++++++++++++++--- Server/server.c | 19 ++++++++++++++-- Server/ssl.c | 32 +++++++++++++++++++++++++++ Server/tw_config.h | 14 ++++++++++-- Server/tw_ssl.h | 4 ++++ example.conf | 11 ++++++++++ 7 files changed, 129 insertions(+), 8 deletions(-) create mode 100644 example.conf diff --git a/Common/log.c b/Common/log.c index 5d812a6..79298c7 100644 --- a/Common/log.c +++ b/Common/log.c @@ -37,7 +37,8 @@ void cm_log(const char* name, const char* log, ...) { i++; if(log[i] == 's') { char* tmp = result; - result = cm_strcat(tmp, va_arg(args, char*)); + char* c = va_arg(args, char*); + result = cm_strcat(tmp, c == NULL ? "(null)" : c); free(tmp); } else if(log[i] == 'd') { int a = va_arg(args, int); diff --git a/Server/config.c b/Server/config.c index 83cb269..c70847a 100644 --- a/Server/config.c +++ b/Server/config.c @@ -6,17 +6,36 @@ #include #include #include +#include #include #include struct tw_config config; +struct tw_config_entry* tw_vhost_match(const char* name, int port) { + int i; + for(i = 0; i < config.vhost_count; i++) { + if(strcmp(config.vhosts[i].name, name) == 0 && config.vhosts[i].port == port) { + return &config.vhosts[i]; + } + } + return &config.root; +} + void tw_config_init(void) { int i; for(i = 0; i < MAX_PORTS + 1; i++) { config.ports[i] = -1; } + for(i = 0; i < MAX_VHOSTS; i++) { + config.vhosts[i].sslkey = NULL; + config.vhosts[i].sslcert = NULL; + } + config.root.sslkey = NULL; + config.root.sslcert = NULL; + config.vhost_count = 0; + gethostname(config.hostname, 1024); } int tw_config_read(const char* path) { @@ -29,6 +48,7 @@ int tw_config_read(const char* path) { char* line = malloc(1); line[0] = 0; int stop = 0; + struct tw_config_entry* current = &config.root; char* vhost = NULL; while(stop == 0) { int c = fread(cbuf, 1, 1, f); @@ -47,23 +67,35 @@ int tw_config_read(const char* path) { } } else if(cm_strcaseequ(r[0], "BeginVirtualHost")) { if(vhost != NULL) { - cm_log("Config", "Already in virtual host section"); + cm_log("Config", "Already in virtual host section at line %d", ln); stop = 1; } else { if(r[1] == NULL) { - cm_log("Config", "Missing virtual host"); + cm_log("Config", "Missing virtual host at line %d", ln); stop = 1; } else { vhost = cm_strdup(r[1]); + current = &config.vhosts[config.vhost_count++]; + int i; + current->name = cm_strdup(vhost); + current->port = 80; + for(i = 0; vhost[i] != 0; i++) { + if(vhost[i] == ':') { + current->name[i] = 0; + current->port = atoi(current->name + i + 1); + break; + } + } } } } else if(cm_strcaseequ(r[0], "EndVirtualHost")) { if(vhost == NULL) { - cm_log("Config", "Not in virtual host section"); + cm_log("Config", "Not in virtual host section at line %d", ln); stop = 1; } else { free(vhost); vhost = NULL; + current = &config.root; } } else if(cm_strcaseequ(r[0], "Listen") || cm_strcaseequ(r[0], "ListenSSL")) { for(i = 1; r[i] != NULL; i++) { @@ -75,6 +107,22 @@ int tw_config_read(const char* path) { ; config.ports[j] = port; } + } else if(cm_strcaseequ(r[0], "SSLKey")) { + if(r[1] == NULL) { + cm_log("Config", "Missing path at line %d", ln); + stop = 1; + } else { + if(current->sslkey != NULL) free(current->sslkey); + current->sslkey = cm_strdup(r[1]); + } + } else if(cm_strcaseequ(r[0], "SSLCertificate")) { + if(r[1] == NULL) { + cm_log("Config", "Missing path at line %d", ln); + stop = 1; + } else { + if(current->sslcert != NULL) free(current->sslcert); + current->sslcert = cm_strdup(r[1]); + } } else { if(r[0] != NULL) { cm_log("Config", "Unknown directive `%s' at line %d", r[0], ln); diff --git a/Server/server.c b/Server/server.c index 32b0658..9d7d3ff 100644 --- a/Server/server.c +++ b/Server/server.c @@ -2,6 +2,7 @@ #include "tw_server.h" +#include "tw_ssl.h" #include "tw_config.h" #include @@ -114,15 +115,27 @@ int tw_server_init(void) { #ifdef __MINGW32__ struct pass_entry { int sock; + int port; bool ssl; }; unsigned int WINAPI tw_server_pass(void* ptr) { int sock = ((struct pass_entry*)ptr)->sock; bool ssl = ((struct pass_entry*)ptr)->ssl; + int port = ((struct pass_entry*)ptR)->port; + free(ptr); #else -void tw_server_pass(int sock, bool ssl) { +void tw_server_pass(int sock, bool ssl, int port) { #endif + SSL_CTX* ctx = NULL; + SSL* s = NULL; + if(ssl) { + ctx = tw_create_ssl_ctx(port); + s = SSL_new(ctx); + SSL_set_fd(s, sock); + if(SSL_accept(s) <= 0) goto cleanup; + } +cleanup: close_socket(sock); #ifdef __MINGW32__ _endthreadex(0); @@ -150,16 +163,18 @@ void tw_server_loop(void) { SOCKADDR claddr; int clen = sizeof(claddr); int sock = accept(sockets[i], (struct sockaddr*)&claddr, &clen); + cm_log("Server", "New connection accepted"); #ifdef __MINGW32__ HANDLE thread; struct pass_entry* e = malloc(sizeof(*e)); e->sock = sock; e->ssl = config.ports[i] & (1ULL << 32); + e->port = config.ports[i]; thread = (HANDLE)_beginthreadex(NULL, 0, tw_server_pass, e, 0, NULL); #else pid_t pid = fork(); if(pid == 0) { - tw_server_pass(sock, config.ports[i] & (1ULL << 32)); + tw_server_pass(sock, config.ports[i] & (1ULL << 32), config.ports[i]); _exit(0); } else { close_socket(sock); diff --git a/Server/ssl.c b/Server/ssl.c index fc3ce95..e5bb8d3 100644 --- a/Server/ssl.c +++ b/Server/ssl.c @@ -1,3 +1,35 @@ /* $Id$ */ #include "tw_ssl.h" + +#include "tw_config.h" + +#include + +#include + +extern struct tw_config config; + +int tw_ssl_cert_cb(SSL* ssl, void* arg) { + const char* s = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + if(s != NULL) { + cm_log("SSL", "Certificate request for %s", s); + } else { + s = config.hostname; + cm_log("SSL", "Could not get the servername, defaulting to the hostname: %s", s); + } + struct tw_config_entry* e = tw_vhost_match(s, (uint64_t)arg); + if(e != NULL && e->sslkey != NULL && e->sslcert != NULL) { + SSL_use_PrivateKey_file(ssl, e->sslkey, SSL_FILETYPE_PEM); + SSL_use_certificate_file(ssl, e->sslcert, SSL_FILETYPE_PEM); + return 1; + } else { + return 0; + } +} + +SSL_CTX* tw_create_ssl_ctx(uint64_t port) { + SSL_CTX* ctx = SSL_CTX_new(TLS_server_method()); + SSL_CTX_set_cert_cb(ctx, tw_ssl_cert_cb, (void*)port); + return ctx; +} diff --git a/Server/tw_config.h b/Server/tw_config.h index d3be0e0..2aa1bb5 100644 --- a/Server/tw_config.h +++ b/Server/tw_config.h @@ -5,17 +5,27 @@ #include -/* I don't think you would listen to 1024 ports */ #define MAX_PORTS 1024 -struct tw_config_entry {}; +#define MAX_VHOSTS 1024 + +struct tw_config_entry { + char* name; + int port; + char* sslkey; + char* sslcert; +}; struct tw_config { uint64_t ports[MAX_PORTS + 1]; /* If port & (1 << 32) is non-zero, it is SSL */ + char hostname[1025]; struct tw_config_entry root; + struct tw_config_entry vhosts[MAX_VHOSTS]; + int vhost_count; }; void tw_config_init(void); int tw_config_read(const char* path); +struct tw_config_entry* tw_vhost_match(const char* name, int port); #endif diff --git a/Server/tw_ssl.h b/Server/tw_ssl.h index ce1d2af..0e2b246 100644 --- a/Server/tw_ssl.h +++ b/Server/tw_ssl.h @@ -3,4 +3,8 @@ #ifndef __TW_SSL_H__ #define __TW_SSL_H__ +#include + +SSL_CTX* tw_create_ssl_ctx(uint64_t port); + #endif diff --git a/example.conf b/example.conf new file mode 100644 index 0000000..2d9b0a7 --- /dev/null +++ b/example.conf @@ -0,0 +1,11 @@ +# $Id$ +# This is an example config + +Listen 8000 8001 8002 8003 8004 +ListenSSL 8443 8444 8445 8446 8447 + +SSLKey key.pem +SSLCertificate cert.pem + +BeginVirtualHost nishinbsd-ssd:8443 +EndVirtualHost