Add SNI
This commit is contained in:
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
Reference in New Issue
Block a user