This commit is contained in:
2021-12-27 16:16:41 +01:00
parent ce91fecc80
commit 9eaa644fa1
4 changed files with 134 additions and 49 deletions

View File

@ -34,7 +34,7 @@ struct timeval client_timeout;
host_config *get_host_config(const char *host) { host_config *get_host_config(const char *host) {
for (int i = 0; i < CONFIG_MAX_HOST_CONFIG; i++) { for (int i = 0; i < CONFIG_MAX_HOST_CONFIG; i++) {
host_config *hc = &config[i]; host_config *hc = &config->hosts[i];
if (hc->type == CONFIG_TYPE_UNSET) break; if (hc->type == CONFIG_TYPE_UNSET) break;
if (strcmp(hc->name, host) == 0) return hc; if (strcmp(hc->name, host) == 0) return hc;
} }

View File

@ -14,11 +14,11 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
host_config *config; t_config *config;
char cert_file[256], key_file[256], geoip_dir[256], dns_server[256]; char geoip_dir[256], dns_server[256];
int config_init() { int config_init() {
int shm_id = shmget(CONFIG_SHM_KEY, CONFIG_MAX_HOST_CONFIG * sizeof(host_config), IPC_CREAT | IPC_EXCL | 0640); int shm_id = shmget(CONFIG_SHM_KEY, sizeof(t_config), IPC_CREAT | IPC_EXCL | 0640);
if (shm_id < 0) { if (shm_id < 0) {
fprintf(stderr, ERR_STR "Unable to create shared memory: %s" CLR_STR "\n", strerror(errno)); fprintf(stderr, ERR_STR "Unable to create shared memory: %s" CLR_STR "\n", strerror(errno));
return -1; return -1;
@ -37,7 +37,7 @@ int config_init() {
return -3; return -3;
} }
config = shm_rw; config = shm_rw;
memset(config, 0, CONFIG_MAX_HOST_CONFIG * sizeof(host_config)); memset(config, 0, sizeof(t_config));
shmdt(shm_rw); shmdt(shm_rw);
config = shm; config = shm;
return 0; return 0;
@ -72,11 +72,13 @@ int config_load(const char *filename) {
fread(conf, 1, len, file); fread(conf, 1, len, file);
fclose(file); fclose(file);
host_config *tmp_config = malloc(CONFIG_MAX_HOST_CONFIG * sizeof(host_config)); t_config *tmp_config = malloc(sizeof(t_config));
memset(tmp_config, 0, CONFIG_MAX_HOST_CONFIG * sizeof(host_config)); memset(tmp_config, 0, sizeof(t_config));
int i = 0; int i = 0;
int j = 0;
int mode = 0; int mode = 0;
char section = 0;
char *ptr = NULL; char *ptr = NULL;
char *source, *target; char *source, *target;
while ((ptr = strtok(ptr == NULL ? conf : NULL, "\n")) != NULL) { while ((ptr = strtok(ptr == NULL ? conf : NULL, "\n")) != NULL) {
@ -85,25 +87,46 @@ int config_load(const char *filename) {
len = strlen(ptr); len = strlen(ptr);
if (ptr[0] == '[') { if (ptr[0] == '[') {
if (ptr[len - 1] != ']') goto err; if (ptr[len - 1] != ']') goto err;
snprintf(tmp_config[i].name, sizeof(tmp_config[i].name), "%.*s", (int) len - 2, ptr + 1); int l = 0;
i++; if (strncmp(ptr, "host", 4) == 0 && (ptr[4] == ' ' || ptr[4] == '\t')) {
ptr += 4;
while (ptr[0] == ' ' || ptr[0] == '\t' || ptr[0] == ']') ptr++;
while (ptr[l] != ' ' && ptr[l] != '\t' && ptr[l] != ']') l++;
if (l == 0) goto err;
snprintf(tmp_config->hosts[i].name, sizeof(tmp_config->hosts[i].name), "%.*s", l, ptr);
i++;
section = 'h';
} else if (strncmp(ptr, "cert", 4) == 0 && (ptr[4] == ' ' || ptr[4] == '\t')) {
ptr += 4;
while (ptr[0] == ' ' || ptr[0] == '\t' || ptr[0] == ']') ptr++;
while (ptr[l] != ' ' && ptr[l] != '\t' && ptr[l] != ']') l++;
if (l == 0) goto err;
snprintf(tmp_config->certs[j].name, sizeof(tmp_config->certs[j].name), "%.*s", l, ptr);
j++;
section = 'c';
} else {
goto err;
}
continue; continue;
} else if (i == 0) { } else if (section == 0) {
if (len > 12 && strncmp(ptr, "certificate", 11) == 0 && (ptr[11] == ' ' || ptr[11] == '\t')) { if (len > 10 && strncmp(ptr, "geoip_dir", 9) == 0 && (ptr[9] == ' ' || ptr[9] == '\t')) {
source = ptr + 11;
target = cert_file;
} else if (len > 12 && strncmp(ptr, "private_key", 11) == 0 && (ptr[11] == ' ' || ptr[11] == '\t')) {
source = ptr + 11;
target = key_file;
} else if (len > 10 && strncmp(ptr, "geoip_dir", 9) == 0 && (ptr[9] == ' ' || ptr[9] == '\t')) {
source = ptr + 9; source = ptr + 9;
target = geoip_dir; target = geoip_dir;
} else if (len > 11 && strncmp(ptr, "dns_server", 10) == 0 && (ptr[10] == ' ' || ptr[10] == '\t')) { } else if (len > 11 && strncmp(ptr, "dns_server", 10) == 0 && (ptr[10] == ' ' || ptr[10] == '\t')) {
source = ptr + 10; source = ptr + 10;
target = dns_server; target = dns_server;
} }
} else { } else if (section == 'c') {
host_config *hc = &tmp_config[i - 1]; cert_config *cc = &tmp_config->certs[j - 1];
if (len > 12 && strncmp(ptr, "certificate", 11) == 0 && (ptr[11] == ' ' || ptr[11] == '\t')) {
source = ptr + 11;
target = cc->full_chain;
} else if (len > 12 && strncmp(ptr, "private_key", 11) == 0 && (ptr[11] == ' ' || ptr[11] == '\t')) {
source = ptr + 11;
target = cc->priv_key;
}
} else if (section == 'h') {
host_config *hc = &tmp_config->hosts[i - 1];
if (len > 8 && strncmp(ptr, "webroot", 7) == 0 && (ptr[7] == ' ' || ptr[7] == '\t')) { if (len > 8 && strncmp(ptr, "webroot", 7) == 0 && (ptr[7] == ' ' || ptr[7] == '\t')) {
source = ptr + 7; source = ptr + 7;
target = hc->local.webroot; target = hc->local.webroot;
@ -112,6 +135,9 @@ int config_load(const char *filename) {
} else { } else {
hc->type = CONFIG_TYPE_LOCAL; hc->type = CONFIG_TYPE_LOCAL;
} }
} else if (len > 5 && strncmp(ptr, "cert", 4) == 0 && (ptr[4] == ' ' || ptr[4] == '\t')) {
source = ptr + 4;
target = hc->cert_name;
} else if (len > 9 && strncmp(ptr, "dir_mode", 8) == 0 && (ptr[8] == ' ' || ptr[8] == '\t')) { } else if (len > 9 && strncmp(ptr, "dir_mode", 8) == 0 && (ptr[8] == ' ' || ptr[8] == '\t')) {
source = ptr + 8; source = ptr + 8;
target = NULL; target = NULL;
@ -155,6 +181,8 @@ int config_load(const char *filename) {
} }
continue; continue;
} }
} else {
goto err;
} }
char *end_ptr = source + strlen(source) - 1; char *end_ptr = source + strlen(source) - 1;
while (source[0] == ' ' || source[0] == '\t') source++; while (source[0] == ' ' || source[0] == '\t') source++;
@ -171,27 +199,43 @@ int config_load(const char *filename) {
strcpy(target, source); strcpy(target, source);
} else if (mode == 1) { } else if (mode == 1) {
if (strcmp(source, "forbidden") == 0) { if (strcmp(source, "forbidden") == 0) {
tmp_config[i - 1].local.dir_mode = URI_DIR_MODE_FORBIDDEN; tmp_config->hosts[i - 1].local.dir_mode = URI_DIR_MODE_FORBIDDEN;
} else if (strcmp(source, "info") == 0) { } else if (strcmp(source, "info") == 0) {
tmp_config[i - 1].local.dir_mode = URI_DIR_MODE_INFO; tmp_config->hosts[i - 1].local.dir_mode = URI_DIR_MODE_INFO;
} else if (strcmp(source, "list") == 0) { } else if (strcmp(source, "list") == 0) {
tmp_config[i - 1].local.dir_mode = URI_DIR_MODE_LIST; tmp_config->hosts[i - 1].local.dir_mode = URI_DIR_MODE_LIST;
} else { } else {
goto err; goto err;
} }
} else if (mode == 2) { } else if (mode == 2) {
tmp_config[i - 1].rev_proxy.port = (unsigned short) strtoul(source, NULL, 10); tmp_config->hosts[i - 1].rev_proxy.port = (unsigned short) strtoul(source, NULL, 10);
} }
} }
free(conf); free(conf);
for (int j = 0; j < i; j++) { for (int k = 0; k < i; k++) {
if (tmp_config[j].type == CONFIG_TYPE_LOCAL) { host_config *hc = &tmp_config->hosts[k];
char *webroot = tmp_config[j].local.webroot; if (hc->type == CONFIG_TYPE_LOCAL) {
char *webroot = tmp_config->hosts[k].local.webroot;
if (webroot[strlen(webroot) - 1] == '/') { if (webroot[strlen(webroot) - 1] == '/') {
webroot[strlen(webroot) - 1] = 0; webroot[strlen(webroot) - 1] = 0;
} }
} }
if (hc->cert_name[0] == 0) goto err2;
int found = 0;
for (int m = 0; m < j; m++) {
if (strcmp(tmp_config->certs[m].name, hc->cert_name) == 0) {
hc->cert = m;
found = 1;
break;
}
}
if (!found) {
err2:
free(tmp_config);
fprintf(stderr, ERR_STR "Unable to parse config file" CLR_STR "\n");
return -2;
}
} }
int shm_id = shmget(CONFIG_SHM_KEY, 0, 0); int shm_id = shmget(CONFIG_SHM_KEY, 0, 0);
@ -207,7 +251,7 @@ int config_load(const char *filename) {
fprintf(stderr, ERR_STR "Unable to attach shared memory (rw): %s" CLR_STR "\n", strerror(errno)); fprintf(stderr, ERR_STR "Unable to attach shared memory (rw): %s" CLR_STR "\n", strerror(errno));
return -4; return -4;
} }
memcpy(shm_rw, tmp_config, CONFIG_MAX_HOST_CONFIG * sizeof(host_config)); memcpy(shm_rw, tmp_config, sizeof(t_config));
free(tmp_config); free(tmp_config);
shmdt(shm_rw); shmdt(shm_rw);
return 0; return 0;

View File

@ -12,6 +12,7 @@
#define CONFIG_SHM_KEY 255642 #define CONFIG_SHM_KEY 255642
#define CONFIG_MAX_HOST_CONFIG 64 #define CONFIG_MAX_HOST_CONFIG 64
#define CONFIG_MAX_CERT_CONFIG 64
#define CONFIG_TYPE_UNSET 0 #define CONFIG_TYPE_UNSET 0
#define CONFIG_TYPE_LOCAL 1 #define CONFIG_TYPE_LOCAL 1
@ -25,6 +26,8 @@
typedef struct { typedef struct {
int type; int type;
char name[256]; char name[256];
char cert_name[256];
int cert;
union { union {
struct { struct {
char hostname[256]; char hostname[256];
@ -38,8 +41,19 @@ typedef struct {
}; };
} host_config; } host_config;
extern host_config *config; typedef struct {
extern char cert_file[256], key_file[256], geoip_dir[256], dns_server[256]; char name[256];
char full_chain[256];
char priv_key[256];
} cert_config;
typedef struct {
host_config hosts[CONFIG_MAX_HOST_CONFIG];
cert_config certs[CONFIG_MAX_CERT_CONFIG];
} t_config;
extern t_config *config;
extern char geoip_dir[256], dns_server[256];
int config_init(); int config_init();

View File

@ -38,6 +38,7 @@ const char *config_file;
int sockets[NUM_SOCKETS]; int sockets[NUM_SOCKETS];
pid_t children[MAX_CHILDREN]; pid_t children[MAX_CHILDREN];
MMDB_s mmdbs[MAX_MMDB]; MMDB_s mmdbs[MAX_MMDB];
SSL_CTX *contexts[CONFIG_MAX_CERT_CONFIG];
void openssl_init() { void openssl_init() {
SSL_library_init(); SSL_library_init();
@ -46,6 +47,21 @@ void openssl_init() {
OpenSSL_add_all_algorithms(); OpenSSL_add_all_algorithms();
} }
static int ssl_servername_cb(SSL *ssl, int *ad, void *arg) {
const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (servername != NULL) {
for (int i = 0; i < CONFIG_MAX_HOST_CONFIG; i++) {
const host_config *conf = &config->hosts[i];
if (conf->type == CONFIG_TYPE_UNSET) break;
if (strcmp(conf->name, servername) == 0) {
SSL_set_SSL_CTX(ssl, contexts[conf->cert]);
break;
}
}
}
return SSL_TLSEXT_ERR_OK;
}
void destroy() { void destroy() {
fprintf(stderr, "\n" ERR_STR "Terminating forcefully!" CLR_STR "\n"); fprintf(stderr, "\n" ERR_STR "Terminating forcefully!" CLR_STR "\n");
int status = 0; int status = 0;
@ -290,29 +306,40 @@ int main(int argc, const char *argv[]) {
client.buf = NULL; client.buf = NULL;
client.buf_len = 0; client.buf_len = 0;
client.buf_off = 0; client.buf_off = 0;
client.ctx = SSL_CTX_new(TLS_server_method());
SSL_CTX_set_options(client.ctx, SSL_OP_SINGLE_DH_USE); for (int i = 0; i < CONFIG_MAX_CERT_CONFIG; i++) {
SSL_CTX_set_verify(client.ctx, SSL_VERIFY_NONE, NULL); const cert_config *conf = &config->certs[i];
SSL_CTX_set_min_proto_version(client.ctx, TLS1_2_VERSION); if (conf->name[0] == 0) break;
SSL_CTX_set_mode(client.ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_cipher_list(client.ctx, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4"); contexts[i] = SSL_CTX_new(TLS_server_method());
SSL_CTX_set_ecdh_auto(client.ctx, 1); SSL_CTX *ctx = contexts[i];
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
SSL_CTX_set_cipher_list(ctx, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
SSL_CTX_set_ecdh_auto(ctx, 1);
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
if (SSL_CTX_use_certificate_chain_file(ctx, conf->full_chain) != 1) {
fprintf(stderr, ERR_STR "Unable to load certificate chain file: %s: %s" CLR_STR "\n",
ERR_reason_error_string(ERR_get_error()), conf->full_chain);
config_unload();
return 1;
}
if (SSL_CTX_use_PrivateKey_file(ctx, conf->priv_key, SSL_FILETYPE_PEM) != 1) {
fprintf(stderr, ERR_STR "Unable to load private key file: %s: %s" CLR_STR "\n",
ERR_reason_error_string(ERR_get_error()), conf->priv_key);
config_unload();
return 1;
}
}
client.ctx = contexts[0];
rev_proxy_preload(); rev_proxy_preload();
if (SSL_CTX_use_certificate_chain_file(client.ctx, cert_file) != 1) {
fprintf(stderr, ERR_STR "Unable to load certificate chain file: %s: %s" CLR_STR "\n",
ERR_reason_error_string(ERR_get_error()), cert_file);
config_unload();
return 1;
}
if (SSL_CTX_use_PrivateKey_file(client.ctx, key_file, SSL_FILETYPE_PEM) != 1) {
fprintf(stderr, ERR_STR "Unable to load private key file: %s: %s" CLR_STR "\n",
ERR_reason_error_string(ERR_get_error()), key_file);
config_unload();
return 1;
}
for (int i = 0; i < NUM_SOCKETS; i++) { for (int i = 0; i < NUM_SOCKETS; i++) {
if (listen(sockets[i], LISTEN_BACKLOG) < 0) { if (listen(sockets[i], LISTEN_BACKLOG) < 0) {
fprintf(stderr, ERR_STR "Unable to listen on socket %i: %s" CLR_STR "\n", i, strerror(errno)); fprintf(stderr, ERR_STR "Unable to listen on socket %i: %s" CLR_STR "\n", i, strerror(errno));