add SNI support, and change domain configuration a bit.

This commit is contained in:
Joris Vink 2013-06-24 11:32:45 +02:00
parent a1b400c400
commit 6026a6d4ee
8 changed files with 276 additions and 156 deletions

View File

@ -4,7 +4,7 @@ CC=gcc
BIN=kore
S_SRC+= src/kore.c src/buf.c src/config.c src/net.c src/spdy.c src/http.c \
src/accesslog.c src/module.c src/utils.c src/zlib_dict.c
src/accesslog.c src/domain.c src/module.c src/utils.c src/zlib_dict.c
S_OBJS= $(S_SRC:.c=.o)
CFLAGS+=-I/usr/local/ssl/include

View File

@ -2,8 +2,6 @@
# Server configuration.
bind 10.211.55.3 443
certfile cert/server.crt
certkey cert/server.key
# The path worker processes will chroot too after starting.
chroot /home/joris/src/kore
@ -42,8 +40,20 @@ load example/example.module
# handler path module_callback
# Example domain that responds to 10.211.55.33.
domain 10.211.55.3
accesslog /var/log/kore_access.log
static /css/style.css serve_style_css
static / serve_index
dynamic ^/[a-z0-9_]*$ serve_profile
domain 10.211.55.3 {
certfile cert/server.crt
certkey cert/server.key
accesslog /var/log/kore_access.log
static /css/style.css serve_style_css
static / serve_index
dynamic ^/[a-z0-9_]*$ serve_profile
}
#domain domain.com {
# certfile cert/other/server.crt
# certkey cert/other/server.key
# accesslog /var/log/other_kore_access.log
# static /css/style.css serve_style_css
# static / serve_index
# dynamic ^/[a-z0-9_]*$ serve_profile
#}

View File

@ -114,13 +114,18 @@ struct kore_worker {
TAILQ_HEAD(kore_worker_h, kore_worker);
struct module_domain {
struct kore_domain {
char *domain;
char *certfile;
char *certkey;
int accesslog;
SSL_CTX *ssl_ctx;
TAILQ_HEAD(, kore_module_handle) handlers;
TAILQ_ENTRY(module_domain) list;
TAILQ_ENTRY(kore_domain) list;
};
TAILQ_HEAD(kore_domain_h, kore_domain);
#define KORE_BUF_INITIAL 128
#define KORE_BUF_INCREMENT KORE_BUF_INITIAL
@ -143,8 +148,6 @@ extern char *chroot_path;
extern char *runas_user;
extern char *kore_module_onload;
extern char *kore_pidfile;
extern char *kore_certfile;
extern char *kore_certkey;
extern u_int16_t cpu_count;
extern u_int8_t worker_count;
@ -152,6 +155,8 @@ extern u_int8_t worker_count;
extern struct listener server;
extern struct kore_worker *worker;
extern struct kore_worker_h kore_workers;
extern struct kore_domain_h domains;
extern struct kore_domain *primary_dom;
void kore_worker_init(void);
void kore_worker_wait(int);
@ -168,6 +173,8 @@ void kore_worker_setcpu(struct kore_worker *);
void kore_event_schedule(int, int, int, void *);
int kore_connection_handle(struct connection *);
int kore_server_accept(struct listener *, struct connection **);
int kore_ssl_sni_cb(SSL *, int *, void *);
int kore_ssl_npn_cb(SSL *, const u_char **, unsigned int *, void *);
u_int64_t kore_time_ms(void);
void kore_log_init(void);
@ -184,14 +191,16 @@ void kore_server_disconnect(struct connection *);
int kore_split_string(char *, char *, char **, size_t);
long long kore_strtonum(const char *, long long, long long, int *);
void kore_domain_init(void);
int kore_domain_new(char *);
void kore_module_load(char *);
void kore_module_reload(void);
int kore_module_loaded(void);
int kore_module_domain_new(char *);
void kore_module_domain_closelogs(void);
void kore_domain_closelogs(void);
void *kore_module_handler_find(char *, char *);
void kore_domain_sslstart(struct kore_domain *);
int kore_module_handler_new(char *, char *, char *, int);
struct module_domain *kore_module_domain_lookup(char *);
struct kore_domain *kore_domain_lookup(const char *);
void fatal(const char *, ...);
void kore_debug_internal(char *, int, const char *, ...);

View File

@ -65,7 +65,7 @@ void
kore_accesslog_worker_init(void)
{
close(accesslog_fd[0]);
kore_module_domain_closelogs();
kore_domain_closelogs();
}
int
@ -75,7 +75,7 @@ kore_accesslog_wait(void)
time_t now;
size_t slen;
int nfds;
struct module_domain *dom;
struct kore_domain *dom;
struct pollfd pfd[1];
struct kore_log_packet logpacket;
char *method, buf[4096], *tbuf;
@ -104,7 +104,7 @@ kore_accesslog_wait(void)
if (len != sizeof(logpacket))
return (KORE_RESULT_ERROR);
if ((dom = kore_module_domain_lookup(logpacket.host)) == NULL) {
if ((dom = kore_domain_lookup(logpacket.host)) == NULL) {
kore_log(LOG_WARNING,
"got accesslog packet for unknown domain: %s",
logpacket.host);

View File

@ -47,9 +47,10 @@ static int configure_chroot(char **);
static int configure_runas(char **);
static int configure_workers(char **);
static int configure_pidfile(char **);
static int configure_accesslog(char **);
static int configure_certfile(char **);
static int configure_certkey(char **);
static int configure_accesslog(char **);
static void domain_sslstart(void);
static struct {
const char *name;
@ -65,13 +66,13 @@ static struct {
{ "runas", configure_runas },
{ "workers", configure_workers },
{ "pidfile", configure_pidfile },
{ "accesslog", configure_accesslog },
{ "certfile", configure_certfile },
{ "certkey", configure_certkey },
{ "accesslog", configure_accesslog },
{ NULL, NULL },
};
static char *current_domain = NULL;
static struct kore_domain *current_domain = NULL;
void
kore_parse_config(const char *config_path)
@ -100,6 +101,9 @@ kore_parse_config(const char *config_path)
*t = ' ';
}
if (!strcmp(p, "}") && current_domain != NULL)
domain_sslstart();
kore_split_string(p, " ", argv, 5);
for (i = 0; config_names[i].name != NULL; i++) {
if (!strcmp(config_names[i].name, argv[0])) {
@ -165,17 +169,25 @@ configure_onload(char **argv)
static int
configure_domain(char **argv)
{
if (argv[1] == NULL)
if (argv[2] == NULL)
return (KORE_RESULT_ERROR);
if (current_domain != NULL)
free(current_domain);
current_domain = kore_strdup(argv[1]);
if (!kore_module_domain_new(current_domain)) {
if (current_domain != NULL) {
kore_debug("previous domain configuration not closed");
return (KORE_RESULT_ERROR);
}
if (strcmp(argv[2], "{")) {
kore_debug("missing { for domain directive");
return (KORE_RESULT_ERROR);
}
if (!kore_domain_new(argv[1])) {
kore_debug("could not create new domain %s", current_domain);
return (KORE_RESULT_ERROR);
}
current_domain = kore_domain_lookup(argv[1]);
return (KORE_RESULT_OK);
}
@ -199,7 +211,8 @@ configure_handler(char **argv)
else
return (KORE_RESULT_ERROR);
if (!kore_module_handler_new(argv[1], current_domain, argv[2], type)) {
if (!kore_module_handler_new(argv[1],
current_domain->domain, argv[2], type)) {
kore_debug("cannot create handler for %s", argv[1]);
return (KORE_RESULT_ERROR);
}
@ -274,65 +287,76 @@ configure_pidfile(char **argv)
return (KORE_RESULT_OK);
}
static int
configure_accesslog(char **argv)
{
if (argv[1] == NULL)
return (KORE_RESULT_ERROR);
if (current_domain == NULL) {
kore_debug("missing domain for accesslog");
return (KORE_RESULT_ERROR);
}
if (current_domain->accesslog != -1) {
kore_debug("domain %s already has an open accesslog",
current_domain->domain);
return (KORE_RESULT_ERROR);
}
current_domain->accesslog = open(argv[1],
O_CREAT | O_APPEND | O_WRONLY, 0755);
if (current_domain->accesslog == -1) {
kore_debug("open(%s): %s", argv[1], errno_s);
return (KORE_RESULT_ERROR);
}
return (KORE_RESULT_OK);
}
static int
configure_certfile(char **argv)
{
if (argv[1] == NULL)
return (KORE_RESULT_ERROR);
if (kore_certfile != NULL) {
kore_debug("duplicate kore_certfile directive specified");
if (current_domain == NULL) {
kore_debug("missing domain for certfile");
return (KORE_RESULT_ERROR);
}
kore_certfile = kore_strdup(argv[1]);
if (current_domain->certfile != NULL) {
kore_debug("domain already has a certfile set");
return (KORE_RESULT_ERROR);
}
current_domain->certfile = kore_strdup(argv[1]);
return (KORE_RESULT_OK);
}
static int
configure_certkey(char **argv)
{
if (argv[1] == NULL)
return (KORE_RESULT_ERROR);
if (kore_certkey != NULL) {
kore_debug("duplicate kore_certkey directive specified");
return (KORE_RESULT_ERROR);
}
kore_certkey = kore_strdup(argv[1]);
return (KORE_RESULT_OK);
}
static int
configure_accesslog(char **argv)
{
struct module_domain *dom;
if (argv[1] == NULL)
return (KORE_RESULT_ERROR);
if (current_domain == NULL) {
kore_debug("missing domain for accesslog");
kore_debug("missing domain for certkey");
return (KORE_RESULT_ERROR);
}
if ((dom = kore_module_domain_lookup(current_domain)) == NULL) {
kore_debug("current_domain not found: (%s)", current_domain);
return (KORE_RESULT_ERROR);
}
if (dom->accesslog != -1) {
kore_debug("domain %s already has an open accesslog",
current_domain);
return (KORE_RESULT_ERROR);
}
dom->accesslog = open(argv[1], O_CREAT | O_APPEND | O_WRONLY, 0755);
if (dom->accesslog == -1) {
kore_debug("open(%s): %s", argv[1], errno_s);
if (current_domain->certkey != NULL) {
kore_debug("domain already has a certkey set");
return (KORE_RESULT_ERROR);
}
current_domain->certkey = kore_strdup(argv[1]);
return (KORE_RESULT_OK);
}
static void
domain_sslstart(void)
{
kore_domain_sslstart(current_domain);
current_domain = NULL;
}

130
src/domain.c Normal file
View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2013 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/queue.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <ctype.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <regex.h>
#include <zlib.h>
#include "spdy.h"
#include "kore.h"
struct kore_domain_h domains;
struct kore_domain *primary_dom = NULL;
void
kore_domain_init(void)
{
TAILQ_INIT(&domains);
}
int
kore_domain_new(char *domain)
{
struct kore_domain *dom;
if (kore_domain_lookup(domain) != NULL)
return (KORE_RESULT_ERROR);
kore_debug("kore_domain_new(%s, %s, %s)", domain);
dom = (struct kore_domain *)kore_malloc(sizeof(*dom));
dom->accesslog = -1;
dom->certfile = NULL;
dom->certkey = NULL;
dom->domain = kore_strdup(domain);
TAILQ_INIT(&(dom->handlers));
TAILQ_INSERT_TAIL(&domains, dom, list);
if (primary_dom == NULL)
primary_dom = dom;
return (KORE_RESULT_OK);
}
void
kore_domain_sslstart(struct kore_domain *dom)
{
kore_debug("kore_domain_sslstart(%s)", dom->domain);
dom->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (dom->ssl_ctx == NULL)
fatal("kore_domain_new(): SSL_ctx_new(): %s", ssl_errno_s);
if (!SSL_CTX_use_certificate_chain_file(dom->ssl_ctx, dom->certfile)) {
fatal("SSL_CTX_use_certificate_chain_file(%s): %s",
dom->certfile, ssl_errno_s);
}
if (!SSL_CTX_use_PrivateKey_file(dom->ssl_ctx, dom->certkey,
SSL_FILETYPE_PEM)) {
fatal("SSL_CTX_use_PrivateKey_file(%s): %s",
dom->certkey, ssl_errno_s);
}
if (!SSL_CTX_check_private_key(dom->ssl_ctx))
fatal("Public/Private key for %s do not match", dom->domain);
SSL_CTX_set_mode(dom->ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(dom->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_options(dom->ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_tlsext_servername_callback(dom->ssl_ctx, kore_ssl_sni_cb);
SSL_CTX_set_next_protos_advertised_cb(dom->ssl_ctx,
kore_ssl_npn_cb, NULL);
free(dom->certfile);
free(dom->certkey);
}
struct kore_domain *
kore_domain_lookup(const char *domain)
{
struct kore_domain *dom;
TAILQ_FOREACH(dom, &domains, list) {
if (!strcmp(dom->domain, domain))
return (dom);
}
return (NULL);
}
void
kore_domain_closelogs(void)
{
struct kore_domain *dom;
TAILQ_FOREACH(dom, &domains, list)
close(dom->accesslog);
}

View File

@ -46,8 +46,6 @@
#include "kore.h"
#include "http.h"
static SSL_CTX *ssl_ctx = NULL;
volatile sig_atomic_t sig_recv;
static TAILQ_HEAD(, connection) disconnected;
static TAILQ_HEAD(, connection) worker_clients;
@ -65,18 +63,15 @@ u_int8_t worker_count = 0;
char *server_ip = NULL;
char *runas_user = NULL;
char *chroot_path = NULL;
char *kore_certkey = NULL;
char *kore_certfile = NULL;
char *kore_pidfile = KORE_PIDFILE_DEFAULT;
static void usage(void);
static void kore_signal(int);
static void kore_write_mypid(void);
static int kore_socket_nonblock(int);
static int kore_server_sslstart(void);
static void kore_server_sslstart(void);
static void kore_server_final_disconnect(struct connection *);
static int kore_server_bind(struct listener *, const char *, int);
static int kore_ssl_npn_cb(SSL *, const u_char **, unsigned int *, void *);
static void
usage(void)
@ -117,6 +112,10 @@ main(int argc, char *argv[])
fatal("please specify a configuration file to use (-c)");
mypid = getpid();
kore_domain_init();
kore_server_sslstart();
kore_parse_config(config_file);
if (!kore_module_loaded())
fatal("no site module was loaded");
@ -129,15 +128,11 @@ main(int argc, char *argv[])
fatal("missing a username to run as");
if ((pw = getpwnam(runas_user)) == NULL)
fatal("user '%s' does not exist", runas_user);
if (kore_certfile == NULL || kore_certkey == NULL)
fatal("missing certificate information");
kore_log_init();
kore_platform_init();
kore_accesslog_init();
if (!kore_server_sslstart())
fatal("cannot initiate SSL");
if (!kore_server_bind(&server, server_ip, server_port))
fatal("cannot bind to %s:%d", server_ip, server_port);
if (daemon(1, 1) == -1)
@ -156,8 +151,6 @@ main(int argc, char *argv[])
free(server_ip);
free(runas_user);
free(kore_certkey);
free(kore_certfile);
for (;;) {
if (sig_recv != 0) {
@ -261,7 +254,7 @@ kore_connection_handle(struct connection *c)
switch (c->state) {
case CONN_STATE_SSL_SHAKE:
if (c->ssl == NULL) {
c->ssl = SSL_new(ssl_ctx);
c->ssl = SSL_new(primary_dom->ssl_ctx);
if (c->ssl == NULL) {
kore_debug("SSL_new(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
@ -429,36 +422,42 @@ kore_worker_entry(struct kore_worker *kw)
exit(0);
}
static int
int
kore_ssl_npn_cb(SSL *ssl, const u_char **data, unsigned int *len, void *arg)
{
kore_debug("kore_ssl_npn_cb(): sending protocols");
*data = (const unsigned char *)KORE_SSL_PROTO_STRING;
*len = strlen(KORE_SSL_PROTO_STRING);
return (SSL_TLSEXT_ERR_OK);
}
int
kore_ssl_sni_cb(SSL *ssl, int *ad, void *arg)
{
struct kore_domain *dom;
const char *sname;
sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
kore_debug("kore_ssl_sni_cb(): received host %s", sname);
if (sname != NULL && (dom = kore_domain_lookup(sname)) != NULL) {
kore_debug("kore_ssl_sni_cb(): Using %s CTX", sname);
SSL_set_SSL_CTX(ssl, dom->ssl_ctx);
return (SSL_TLSEXT_ERR_OK);
}
return (SSL_TLSEXT_ERR_NOACK);
}
static void
kore_server_sslstart(void)
{
kore_debug("kore_server_sslstart()");
SSL_library_init();
SSL_load_error_strings();
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (ssl_ctx == NULL) {
kore_debug("SSL_ctx_new(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
}
if (!SSL_CTX_use_certificate_chain_file(ssl_ctx, kore_certfile)) {
kore_debug("SSL_CTX_use_certificate_file(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
}
if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, kore_certkey,
SSL_FILETYPE_PEM)) {
kore_debug("SSL_CTX_use_PrivateKey_file(): %s", ssl_errno_s);
return (KORE_RESULT_ERROR);
}
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, kore_ssl_npn_cb, NULL);
return (KORE_RESULT_OK);
}
static int
@ -575,17 +574,6 @@ kore_socket_nonblock(int fd)
return (KORE_RESULT_OK);
}
static int
kore_ssl_npn_cb(SSL *ssl, const u_char **data, unsigned int *len, void *arg)
{
kore_debug("kore_ssl_npn_cb(): sending protocols");
*data = (const unsigned char *)KORE_SSL_PROTO_STRING;
*len = strlen(KORE_SSL_PROTO_STRING);
return (SSL_TLSEXT_ERR_OK);
}
static void
kore_write_mypid(void)
{

View File

@ -46,8 +46,6 @@ static char *mod_name = NULL;
static time_t mod_last_mtime = 0;
char *kore_module_onload = NULL;
static TAILQ_HEAD(, module_domain) domains;
void
kore_module_load(char *module_name)
{
@ -81,7 +79,7 @@ kore_module_load(char *module_name)
void
kore_module_reload(void)
{
struct module_domain *dom;
struct kore_domain *dom;
struct kore_module_handle *hdlr;
void (*onload)(void);
@ -116,28 +114,11 @@ kore_module_loaded(void)
return (mod_handle != NULL ? KORE_RESULT_OK : KORE_RESULT_ERROR);
}
int
kore_module_domain_new(char *domain)
{
struct module_domain *dom;
if (kore_module_domain_lookup(domain) != NULL)
return (KORE_RESULT_ERROR);
dom = (struct module_domain *)kore_malloc(sizeof(*dom));
dom->accesslog = -1;
dom->domain = kore_strdup(domain);
TAILQ_INIT(&(dom->handlers));
TAILQ_INSERT_TAIL(&domains, dom, list);
return (KORE_RESULT_OK);
}
int
kore_module_handler_new(char *path, char *domain, char *func, int type)
{
void *addr;
struct module_domain *dom;
struct kore_domain *dom;
struct kore_module_handle *hdlr;
kore_debug("kore_module_handler_new(%s, %s, %s, %d)", path,
@ -149,7 +130,7 @@ kore_module_handler_new(char *path, char *domain, char *func, int type)
return (KORE_RESULT_ERROR);
}
if ((dom = kore_module_domain_lookup(domain)) == NULL)
if ((dom = kore_domain_lookup(domain)) == NULL)
return (KORE_RESULT_ERROR);
hdlr = (struct kore_module_handle *)kore_malloc(sizeof(*hdlr));
@ -175,10 +156,10 @@ kore_module_handler_new(char *path, char *domain, char *func, int type)
void *
kore_module_handler_find(char *domain, char *path)
{
struct module_domain *dom;
struct kore_domain *dom;
struct kore_module_handle *hdlr;
if ((dom = kore_module_domain_lookup(domain)) == NULL)
if ((dom = kore_domain_lookup(domain)) == NULL)
return (NULL);
TAILQ_FOREACH(hdlr, &(dom->handlers), list) {
@ -193,25 +174,3 @@ kore_module_handler_find(char *domain, char *path)
return (NULL);
}
struct module_domain *
kore_module_domain_lookup(char *domain)
{
struct module_domain *dom;
TAILQ_FOREACH(dom, &domains, list) {
if (!strcmp(dom->domain, domain))
return (dom);
}
return (NULL);
}
void
kore_module_domain_closelogs(void)
{
struct module_domain *dom;
TAILQ_FOREACH(dom, &domains, list)
close(dom->accesslog);
}