updated hashmap, rewritten name_descs.c

This commit is contained in:
aiden 2023-04-20 17:52:17 +01:00
parent d3235a80cc
commit 71375a1f55
Signed by: aiden
GPG Key ID: EFA9C74AEBF806E0
50 changed files with 780 additions and 514 deletions

6
.gitmodules vendored
View File

@ -1,4 +1,4 @@
[submodule "core/hashmap"]
path = core/hashmap
[submodule "hashmap"]
path = hashmap
url = https://git.tcp.direct/aiden/hashmap.git
branch = main
branch = main

View File

@ -1,6 +1,6 @@
ISC License
Copyright (c) 2022, aiden (aiden@citalopram.reviews)
Copyright (c) 2023, aiden (aiden@cmp.bz)
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__services__h
#define bidirectiond_core__services__h
#ifndef bidirectiond__services__h
#define bidirectiond__services__h
#include <stdbool.h>
#include <stddef.h>
@ -8,7 +8,7 @@
#include "../src/headers/bdd_event.h"
#include "../src/headers/bdd_service.h"
#include "../src/headers/bdd_name_descs.h"
#include "../src/headers/name_descs.h"
#include "../src/headers/bdd_cont.h"
#include "../src/headers/bdd_shutdown_status.h"
#include "../src/headers/bidirectiond_n_io.h"
@ -43,7 +43,6 @@ void bdd_set_associated(
);
void *bdd_get_associated(struct bdd_conversation *conversation);
bool bdd_name_descs_add_service_instance(
struct bdd_name_descs *name_descs,
const char *scope,
size_t scope_sz,
const struct bdd_service *service,

25
bdd/headers/settings.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef bidirectiond__settings__h
#define bidirectiond__settings__h
#include <openssl/ssl.h>
#include <stdbool.h>
#include "../src/headers/name_descs.h"
#include "../src/headers/bdd_settings.h"
#include "../src/headers/bdd_service.h"
#include "../src/headers/bdd_stop.h"
struct bdd_name_descs;
struct bdd_instance *bdd_go(struct bdd_settings settings);
void bdd_wait(void);
void bdd_destroy(void);
void bdd_name_descs_use_cert_pkey(
X509 *x509,
EVP_PKEY *pkey
);
bool bdd_name_descs_create(uint16_t n_threads);
void bdd_name_descs_destroy(void);
#endif

View File

@ -1,4 +1,5 @@
#include <errno.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <openssl/ssl.h>
#include <poll.h>
@ -11,12 +12,14 @@
#include "headers/instance.h"
#include "headers/accept.h"
#include "headers/serve.h"
#include "headers/unlikely.h"
#include "headers/debug_log.h"
#include "headers/conversations.h"
#include "headers/name_descs.h"
#include "headers/bdd_service.h"
#include "headers/bdd_stop.h"
#include "headers/hashmap.h"
int bdd_alpn_cb(
SSL *client_ssl,
@ -24,9 +27,9 @@ int bdd_alpn_cb(
unsigned char *outlen,
const unsigned char *_,
unsigned int __,
struct bdd_conversation *conversation
struct bdd_ssl_cb_ctx *ctx
) {
const unsigned char *protocol_name = conversation->aopn.pn.protocol_name;
const unsigned char *protocol_name = ctx->protocol_name;
if (protocol_name == NULL) {
return SSL_TLSEXT_ERR_NOACK;
}
@ -35,9 +38,10 @@ int bdd_alpn_cb(
return SSL_TLSEXT_ERR_OK;
}
int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversation) {
int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_ssl_cb_ctx *ctx) {
struct bdd_conversation *conversation = ctx->conversation;
struct hashmap *name_descs = bdd_gv.name_descs;
struct hashmap_key key = HASHMAP_KEY_INITIALIZER;
struct hashmap_key key;
int r = SSL_CLIENT_HELLO_ERROR;
const unsigned char *extension;
size_t extension_sz;
@ -47,7 +51,7 @@ int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversat
if (extension == NULL) {
return SSL_CLIENT_HELLO_ERROR;
}
if (extension_sz <= 4) {
if (extension_sz < 5) {
return SSL_CLIENT_HELLO_ERROR;
}
if (unlikely(extension[2] != TLSEXT_NAMETYPE_host_name)) {
@ -55,9 +59,15 @@ int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversat
}
size_t name_sz = (size_t)ntohs(*(unsigned short int *)(&(extension[3])));
const unsigned char *name = (const unsigned char *)&(extension[5]);
if (extension_sz != 5 + name_sz) {
return SSL_CLIENT_HELLO_ERROR;
}
const char *name = (const char *)&(extension[5]);
bdd_name_trim(name, &(name_sz));
name = bdd_name(name, &(name_sz));
if (unlikely(name == NULL)) {
return SSL_CLIENT_HELLO_ERROR;
}
const unsigned char *alpn;
size_t alpn_sz;
@ -81,16 +91,16 @@ int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversat
uint8_t found_req = 0;
for (size_t idx = 0;;) {
hashmap_key_obtain(
name_descs,
&(key),
&(name[idx]),
name_sz
hashmap_key(
(void *)&(name[idx]),
name_sz,
&(key)
);
struct bdd_name_desc *name_desc;
if (hashmap_get(name_descs, &(key), (void *)&(name_desc))) {
if (hashmap_cas(name_descs, ctx->area, &(key), (void **)&(name_desc), NULL, hashmap_cas_get, (void *)1) == hashmap_cas_again) {
if (!(found_req & 0b01) && name_desc->x509 != NULL) {
found_req |= 0b01;
// this does up the rc
SSL_use_certificate(client_ssl, name_desc->x509);
SSL_use_PrivateKey(client_ssl, name_desc->pkey);
}
@ -116,8 +126,8 @@ int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversat
if (found == NULL) {
// ...then use this service
found = inst;
assert(conversation->aopn.pn.protocol_name == NULL);
assert(conversation->aopn.pn.cstr_protocol_name == NULL);
assert(ctx->protocol_name == NULL);
assert(ctx->cstr_protocol_name == NULL);
}
// skip the for loop
goto alpn_find_iter;
@ -128,6 +138,7 @@ int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversat
uint8_t alpn_len = alpn[alpn_idx];
// bounds checking
if (alpn_len == 0 || alpn_sz - 1 - alpn_idx < alpn_len) {
pthread_rwlock_unlock(&(name_desc->rwlock));
return SSL_CLIENT_HELLO_ERROR;
}
// loop through the list of the service's supported protocols' names,
@ -141,8 +152,8 @@ int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversat
) == 0
) {
alpn_sz = alpn_idx; // includes the length byte
conversation->aopn.pn.protocol_name = &(alpn[alpn_idx]);
conversation->aopn.pn.cstr_protocol_name = sp[sp_idx];
ctx->protocol_name = &(alpn[alpn_idx]);
ctx->cstr_protocol_name = sp[sp_idx];
found = inst;
// the rest of the service's implemented protocols
// cannot be more preferred by the client
@ -166,30 +177,28 @@ int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversat
found_req |= 0b10;
}
}
pthread_rwlock_unlock(&(name_desc->rwlock));
if (found_req == 0b11) {
break;
}
}
if (name_sz == 0) {
*alert = SSL_AD_UNRECOGNIZED_NAME;
goto out;
return SSL_AD_UNRECOGNIZED_NAME;
}
do {
idx += 1;
name_sz -= 1;
} while (name_sz != 0 && name[idx] != '.');
}
r = SSL_CLIENT_HELLO_SUCCESS;
out:;
hashmap_key_release(bdd_gv.name_descs, &(key), false);
return r;
return SSL_CLIENT_HELLO_SUCCESS;
}
enum bdd_cont bdd_accept_continue(struct bdd_conversation *conversation) {
enum bdd_cont bdd_accept_continue(struct bdd_ssl_cb_ctx *ctx) {
struct bdd_conversation *conversation = ctx->conversation;
struct bdd_io *io = conversation->io_array;
SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(io->io.ssl);
SSL_CTX_set_client_hello_cb(ssl_ctx, (void *)bdd_hello_cb, conversation);
SSL_CTX_set_alpn_select_cb(ssl_ctx, (void *)bdd_alpn_cb, conversation);
int r = SSL_accept(io->io.ssl);
if (r <= 0) {
r = SSL_get_error(io->io.ssl, r);
@ -203,9 +212,9 @@ enum bdd_cont bdd_accept_continue(struct bdd_conversation *conversation) {
struct bdd_service_instance *service_inst = conversation->sosi.service_instance;
conversation->sosi.service = service_inst->service;
const char *cstr_protocol_name = conversation->aopn.pn.cstr_protocol_name;
conversation->aopn.associated.data = NULL;
conversation->aopn.associated.destructor = NULL;
const char *cstr_protocol_name = ctx->cstr_protocol_name;
conversation->associated.data = NULL;
conversation->associated.destructor = NULL;
conversation->state = bdd_conversation_established;
struct sockaddr sockaddr;

View File

@ -15,7 +15,7 @@
#include "headers/bdd_event.h"
void *bdd_get_associated(struct bdd_conversation *conversation) {
return conversation->aopn.associated.data;
return conversation->associated.data;
}
void bdd_set_associated(
struct bdd_conversation *conversation,
@ -23,11 +23,11 @@ void bdd_set_associated(
void (*destructor)(void *)
) {
assert(conversation != NULL);
if (conversation->aopn.associated.destructor != NULL) {
conversation->aopn.associated.destructor(conversation->aopn.associated.data);
if (conversation->associated.destructor != NULL) {
conversation->associated.destructor(conversation->associated.data);
}
conversation->aopn.associated.data = data;
conversation->aopn.associated.destructor = destructor;
conversation->associated.data = data;
conversation->associated.destructor = destructor;
return;
}
@ -94,8 +94,8 @@ struct bdd_conversation *bdd_conversation_obtain(int epoll_fd) {
conversation->n_blocking = 0;
conversation->n_in_epoll_with_events = 0;
conversation->n_ev = 0;
conversation->aopn.pn.protocol_name = NULL;
conversation->aopn.pn.cstr_protocol_name = NULL;
conversation->associated.data = NULL;
conversation->associated.destructor = NULL;
return conversation;
}
void bdd_conversation_discard(struct bdd_conversation *conversation) {

View File

@ -1,24 +1,25 @@
#ifndef bidirectiond_core__accept__h
#define bidirectiond_core__accept__h
#ifndef bidirectiond__accept__h
#define bidirectiond__accept__h
#include <hashmap/hashmap.h>
#include "bdd_cont.h"
struct bdd_conversation;
struct bdd_io;
struct bdd_ssl_cb_ctx;
int bdd_alpn_cb(
SSL *client_ssl,
const unsigned char **out,
unsigned char *outlen,
const unsigned char *_,
unsigned int __,
struct bdd_conversation *conversation
struct bdd_ssl_cb_ctx *ctx
);
int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_conversation *conversation);
struct bdd_ssl_cb_ctx;
int bdd_hello_cb(SSL *client_ssl, int *alert, struct bdd_ssl_cb_ctx *ctx);
struct bdd_worker_data;
void bdd_accept(struct bdd_worker_data *worker_data);
enum bdd_cont bdd_connect_continue(struct bdd_io *io);
enum bdd_cont bdd_accept_continue(struct bdd_conversation *conversation);
enum bdd_cont bdd_accept_continue(struct bdd_ssl_cb_ctx *ctx);
#endif

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__bdd_cont__h
#define bidirectiond_core__bdd_cont__h
#ifndef bidirectiond__bdd_cont__h
#define bidirectiond__bdd_cont__h
enum bdd_cont {
bdd_cont_conversation_discard,

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__bdd_event__h
#define bidirectiond_core__bdd_event__h
#ifndef bidirectiond__bdd_event__h
#define bidirectiond__bdd_event__h
#include "bidirectiond_n_io.h"

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__bdd_io__h
#define bidirectiond_core__bdd_io__h
#ifndef bidirectiond__bdd_io__h
#define bidirectiond__bdd_io__h
#include <openssl/ssl.h>
#include <stdint.h>

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__bdd_service__h
#define bidirectiond_core__bdd_service__h
#ifndef bidirectiond__bdd_service__h
#define bidirectiond__bdd_service__h
#include <stddef.h>
#include <stdbool.h>
@ -20,7 +20,6 @@ struct bdd_service {
void (*instance_info_destructor)(void *instance_info);
bool (*instantiate)(
struct bdd_name_descs *name_descs,
const struct bdd_service *service,
size_t n_arguments,
const char **arguments

View File

@ -1,17 +1,14 @@
#ifndef bidirectiond_core__bdd_settings__h
#define bidirectiond_core__bdd_settings__h
#ifndef bidirectiond__bdd_settings__h
#define bidirectiond__bdd_settings__h
#include <stdint.h>
#include <signal.h>
struct bdd_settings {
struct bdd_name_descs *name_descs;
int epoll_timeout;
int n_conversations;
int n_epoll_oevents;
unsigned short int n_worker_threads;
sigset_t sigmask;

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__bdd_shutdown_status__h
#define bidirectiond_core__bdd_shutdown_status__h
#ifndef bidirectiond__bdd_shutdown_status__h
#define bidirectiond__bdd_shutdown_status__h
enum bdd_shutdown_status {
bdd_shutdown_conversation_discard,

View File

@ -0,0 +1,6 @@
#ifndef bidirectiond__bdd_stop__h
#define bidirectiond__bdd_stop__h
void bdd_stop(void);
#endif

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__conversations__h
#define bidirectiond_core__conversations__h
#ifndef bidirectiond__conversations__h
#define bidirectiond__conversations__h
#include <pthread.h>
#include <stdbool.h>
@ -55,13 +55,7 @@ struct bdd_conversation {
bdd_io_id n_ev;
union {
struct bdd_associated associated;
struct {
const unsigned char *protocol_name;
const char *cstr_protocol_name;
} pn;
} aopn;
struct bdd_associated associated;
};
enum bdd_conversation_init_status {

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__debug_log__h
#define bidirectiond_core__debug_log__h
#ifndef bidirectiond__debug_log__h
#define bidirectiond__debug_log__h
#ifdef NDEBUG

37
bdd/src/headers/hashmap.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef bidriectiond__hashmap__h
#define bidriectiond__hashmap__h
#include <stdbool.h>
#include <stdint.h>
static bool chcd(char ch, uint8_t *cd) {
if (ch >= '0' && ch <= '9') {
*cd = ch - '0';
} else if (ch >= 'a' && ch <= 'z') {
*cd = ch - 'a' + 10;
} else if (ch == '-') {
*cd = 10 + 26;
} else {
return false;
}
return true;
}
static uint32_t HASHMAP_HASH_FUNCTION(char *input, uint32_t sz) {
uint8_t bytes[4] = { 0, 0, 0, 0, };
uint8_t prev[4] = { 0, 0, 0, 0, };
uint8_t bytes_idx = 0, cd;
for (uint32_t idx = 0; idx < sz; ++idx) {
if (!chcd(input[idx], &(cd))) {
*(uint32_t *)bytes *= 37;
bytes_idx = 0;
continue;
}
bytes[bytes_idx] += ((idx + cd) * (prev[bytes_idx] + 1));
prev[bytes_idx] = cd;
bytes_idx = (bytes_idx + 1) & 0b11;
}
return *(uint32_t *)bytes;
}
#include <hashmap.h>
#endif

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__instance__h
#define bidirectiond_core__instance__h
#ifndef bidirectiond__instance__h
#define bidirectiond__instance__h
#include <signal.h>
#include <stdatomic.h>

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__name_descs__h
#define bidirectiond_core__name_descs__h
#ifndef bidirectiond__name_descs__h
#define bidirectiond__name_descs__h
#include <openssl/ssl.h>
@ -10,11 +10,16 @@ struct bdd_service_instance {
struct bdd_service_instance *next;
};
struct bdd_name_desc {
// one writer, multiple readers
// only protects this struct's members!! (obviously not the struct itself!!)
pthread_rwlock_t rwlock;
X509 *x509;
EVP_PKEY *pkey;
struct bdd_service_instance *service_instances;
};
void bdd_name_trim(const unsigned char *name, size_t *name_sz);
const char *bdd_name(const char *name, size_t *name_sz);
#endif

26
bdd/src/headers/serve.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef bidirectiond__serve__h
#define bidirectiond__serve__h
#include <sys/epoll.h>
#include "timeout_list.h"
struct hashmap_area;
struct bdd_conversation;
struct bdd_ssl_cb_ctx {
struct hashmap_area *area;
struct bdd_conversation *conversation;
const unsigned char *protocol_name;
const char *cstr_protocol_name;
};
struct bdd_worker_data {
int epoll_fd;
int serve_fd;
SSL_CTX *ssl_ctx;
struct bdd_ssl_cb_ctx ssl_cb_ctx;
struct bdd_tl timeout_list;
struct epoll_event events[];
};
void *bdd_serve(struct bdd_worker_data *worker_data);
#endif

View File

@ -1,5 +1,5 @@
#ifndef bidirectiond_core__timeout_list__h
#define bidirectiond_core__timeout_list__h
#ifndef bidirectiond__timeout_list__h
#define bidirectiond__timeout_list__h
#include <pthread.h>
#include "conversations.h"

View File

@ -7,6 +7,7 @@
#include <stdint.h>
#include <string.h>
#include "headers/hashmap.h"
#include "headers/instance.h"
#include "headers/conversations.h"
#include "headers/bdd_settings.h"
@ -21,8 +22,6 @@ struct bdd_gv bdd_gv = {
.n_running_threads_mutex = PTHREAD_MUTEX_INITIALIZER,
.n_running_threads_cond = PTHREAD_COND_INITIALIZER,
.name_descs = NULL,
.eventfd = -1,
@ -104,6 +103,7 @@ void bdd_destroy(void) {
struct bdd_worker_data *worker = bdd_gv_worker(idx);
close(worker->epoll_fd);
SSL_CTX_free(worker->ssl_ctx);
hashmap_area_release(bdd_gv.name_descs, worker->ssl_cb_ctx.area);
}
for (
@ -126,12 +126,12 @@ bool bdd_go(struct bdd_settings settings) {
if (
settings.sockfds == NULL ||
settings.n_conversations <= 0 ||
settings.n_epoll_oevents <= 0 ||
settings.name_descs == NULL ||
settings.n_worker_threads <= 0
settings.n_epoll_oevents <= 0
) {
return false;
}
bdd_gv.n_workers = sysconf(_SC_NPROCESSORS_ONLN);
bool locked = false;
@ -158,8 +158,6 @@ bool bdd_go(struct bdd_settings settings) {
// epoll
bdd_gv.n_epoll_oevents = settings.n_epoll_oevents;
bdd_gv.epoll_timeout = settings.epoll_timeout;
// name_descs
bdd_gv.name_descs = settings.name_descs;
// conversations
bdd_gv.n_conversations = settings.n_conversations;
bdd_gv.conversations = malloc(
@ -168,7 +166,7 @@ bool bdd_go(struct bdd_settings settings) {
((
sizeof(struct bdd_worker_data) +
(settings.n_epoll_oevents * sizeof(struct epoll_event))
) * settings.n_worker_threads) // workers
) * bdd_gv.n_workers) // workers
);
if (bdd_gv.conversations == NULL) {
goto err;
@ -201,10 +199,9 @@ bool bdd_go(struct bdd_settings settings) {
locked = true;
struct bdd_worker_data *worker_data = (struct bdd_worker_data *)&(bdd_gv.available_conversations.ids[settings.n_conversations]);
bdd_gv.worker = worker_data;
bdd_gv.n_workers = settings.n_worker_threads;
#define next_worker_data \
(struct bdd_worker_data *)((char *)worker_data + sizeof(struct bdd_worker_data) + (sizeof(struct epoll_event) * settings.n_epoll_oevents))
for (bdd_gv.workers_idx = 0; bdd_gv.workers_idx < settings.n_worker_threads; ++bdd_gv.workers_idx) {
for (bdd_gv.workers_idx = 0; bdd_gv.workers_idx < bdd_gv.n_workers; ++bdd_gv.workers_idx) {
int epoll_fd = epoll_create1(0);
SSL_CTX *ssl_ctx = bdd_ssl_ctx_skel();
bdd_tl_init(&(worker_data->timeout_list));
@ -217,6 +214,9 @@ bool bdd_go(struct bdd_settings settings) {
};
worker_data->epoll_fd = epoll_fd;
worker_data->ssl_ctx = ssl_ctx;
worker_data->ssl_cb_ctx.area = hashmap_area(bdd_gv.name_descs);
SSL_CTX_set_client_hello_cb(ssl_ctx, (void *)bdd_hello_cb, &(worker_data->ssl_cb_ctx));
SSL_CTX_set_alpn_select_cb(ssl_ctx, (void *)bdd_alpn_cb, &(worker_data->ssl_cb_ctx));
worker_data->serve_fd = settings.sockfds[bdd_gv.workers_idx];
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, worker_data->serve_fd, &(event)) != 0) {
goto worker_create_err;

537
bdd/src/name_descs.c Normal file
View File

@ -0,0 +1,537 @@
#include <limits.h>
#include <pthread.h>
#include <stdbool.h>
#include <stddef.h>
#include <openssl/x509v3.h>
#include <string.h>
#include "headers/hashmap.h"
#include "headers/name_descs.h"
#include "headers/bdd_service.h"
#include "headers/instance.h"
#define HASHMAP bdd_gv.name_descs
static struct hashmap_area *AREA = NULL;
// name_descs: hashmap of name_desc
// name_desc: see `struct bdd_name_desc` in name_descs.h
// struct bdd_name_desc
static struct bdd_name_desc *alloc_name_desc(void) {
struct bdd_name_desc *name_desc = malloc(sizeof(struct bdd_name_desc));
if (name_desc == NULL) {
return NULL;
}
if (pthread_rwlock_init(&(name_desc->rwlock), NULL) != 0) {
free(name_desc);
return NULL;
}
name_desc->x509 = NULL;
name_desc->pkey = NULL;
name_desc->service_instances = NULL;
return name_desc;
}
static inline void remove_cert_pkey(struct bdd_name_desc *name_desc) {
if (name_desc->x509 == NULL) {
assert(name_desc->pkey == NULL);
return;
}
assert(name_desc->pkey != NULL);
// misleading function name; it
// actually decs the ref count and
// frees the shit if the rc hits 0
X509_free(name_desc->x509);
EVP_PKEY_free(name_desc->pkey);
name_desc->x509 = NULL;
name_desc->pkey = NULL;
return;
}
static void remove_service_insts(struct bdd_name_desc *name_desc) {
for (
struct bdd_service_instance **service_inst = &(name_desc->service_instances);
(*service_inst) != NULL;
) {
struct bdd_service_instance *curr = (*service_inst);
(*service_inst) = curr->next;
if (curr->instance_info != NULL) {
curr->service->instance_info_destructor((void *)curr->instance_info);
}
free(curr);
}
return;
}
static bool add_service_inst(
struct bdd_name_desc *name_desc,
struct bdd_service_instance *service_inst
) {
const char *const *inst_sp = service_inst->service->supported_protocols;
// iterate over the service instances
// currently reachable from this name
struct bdd_service_instance **curr = &(name_desc->service_instances);
for (; (*curr) != NULL; curr = &((*curr)->next)) {
const char *const *curr_sp = (*curr)->service->supported_protocols;
// services without a protocol list can, with low
// priority (see: accept.c), handle any protocol
// a NULL protocol list is effectively a wildcard
if (inst_sp == NULL || curr_sp == NULL) {
// if inst_sp is NULL, and curr_sp is NULL, then
// return false as to not have multiple wildcard services
if (inst_sp == curr_sp) {
return false;
}
continue;
}
// prevent conflicts where a protocol
// is listed by multiple services
for (size_t idx = 0; curr_sp[idx]; ++idx) {
for (size_t idx2 = 0; inst_sp[idx2]; ++idx2) {
if (strcmp(curr_sp[idx], inst_sp[idx2]) == 0) {
return false;
}
}
}
}
(*curr) = service_inst;
return true;
}
static inline void set_cert_pkey(struct bdd_name_desc *name_desc, X509 *x509, EVP_PKEY *pkey) {
name_desc->x509 = x509;
name_desc->pkey = pkey;
return;
}
static void free_name_desc(struct bdd_name_desc *name_desc) {
pthread_rwlock_destroy(&(name_desc->rwlock));
remove_cert_pkey(name_desc);
remove_service_insts(name_desc);
free(name_desc);
return;
}
// name_descs hashmap
static bool punycode_check(const char *input, unsigned int len, unsigned int n_basic) {
// adapted from https://www.rfc-editor.org/rfc/rfc3492#appendix-C
enum {
base = 36, initial_bias = 72, initial_n = 0x80, tmin = 1, tmax = 26,
skew = 38, damp = 700,
};
unsigned int
n = initial_n,
bias = initial_bias,
out = n_basic;
// process after delimiter
for (
unsigned int i = 0, in = 0, oldi;
in < len; // break after in >= len
++out
) {
oldi = i;
unsigned int
w = 1,
k = base;
for (;; k += base) {
if (in == len) {
return false;
}
unsigned int digit = input[in++];
if (digit - 48 < 10) {
digit -= 22;
} else if (digit - 65 < 26) {
digit -= 65;
} else if (digit - 97 < 26) {
digit -= 97;
} else {
return false;
}
if (digit >= base) {
return false;
}
if (digit > (UINT_MAX - i) / w) {
// `i += digit * w` would overflow
return false;
}
i += digit * w;
unsigned int t;
if (k <= bias) {
t = tmin;
} else if (k >= bias + tmax) {
t = tmax;
} else {
t = k - bias;
}
if (digit < t) {
break;
}
if (w > UINT_MAX / (base - t)) {
// `w *= (base - t)` would overflow
return false;
}
w *= (base - t);
}
// `out + 1` to adapt for the character we're processing
// (we'll increment `out` after this iteration with `++out` in the for loop's post statement)
unsigned int numpoints = out + 1;
unsigned int delta = (i - oldi) / (oldi == 0 ? damp : 2);
delta += delta / numpoints;
for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base) {
delta /= base - tmin;
}
bias = k + (base - tmin + 1) * delta / (delta + skew);
// add the amount of times wrapped around to n
if (i / (out + 1) > UINT_MAX - n) {
// `n += i / (out + 1)` would overflow
return false;
}
n += i / (out + 1);
// wrap i around
i %= (out + 1);
// to-do: xn--iea should return false (uppercase; \u0114)
// (we already have `i` and `n`)
// i'm not passionate enough to implement this; i don't
// get paid enough ($0) and i'm rich anyway ($999,999,999).
// am i the richest person ever? prolly.
}
return true;
}
// idna2008
const char *bdd_name(const char *name, size_t *name_sz) {
size_t sz = *name_sz;
size_t idx = 0;
if (sz >= 1 && name[sz - 1] == '.') {
// conceptually remove the period
// from the end of the string
sz -= 1;
}
// max length for a fully-qualified dns
// name is 255. if the domain name passed
// to the function ends with a period, then
// we decrement its size by 1. this code will
// then treat the dns name as though it does end
// with a period. (since the dns name is assumed to
// end with a period, the maximum amount of octets
// that can come before it must be 254.)
if (sz > 254) {
return NULL;
}
bool req_prd;
if (sz > 0 && name[0] == '*') {
// conceptually remove the
// asterisk from the string
sz -= 1;
name += 1;
req_prd = true;
} else {
req_prd = false;
}
if (sz > 0 && name[0] == '.') {
if (sz == 254) {
// invalid wildcard; name
// guaranteed to exceed 255 octets
return NULL;
}
// skip period
idx = 1;
} else if (req_prd) {
// a period MUST follow an asterisk
return NULL;
}
if (sz == 0) {
goto success;
}
bool name_contains_alphabetic_character = false;
enum label_type { nr_ldh, a, }
label_type = nr_ldh;
size_t
label_sz = 0,
dash_idx;
for (;; ++idx) {
if (idx == sz || name[idx] == '.') {
if (label_sz == 0) {
return NULL;
}
if (label_type == a) {
unsigned int label_idx = idx - label_sz;
unsigned int before_idx = label_idx + 4 /* xn-- */;
unsigned int
n_after_delim = idx - (dash_idx + 1),
n_before_delim = dash_idx < before_idx ? 0 : dash_idx - before_idx;
if (n_after_delim == 0 || !punycode_check(&(name[dash_idx + 1]), n_after_delim, n_before_delim)) {
return NULL;
}
}
if (idx == sz) {
break;
} else {
label_sz = 0;
label_type = nr_ldh;
continue;
}
}
if (label_sz == 63) {
return NULL;
}
if (name[idx] == '-') {
dash_idx = idx;
if (
// first character in label
label_sz == 0 ||
// last character in the entire string
// or the last character of the label
(idx + 1 == sz || name[idx + 1] == '.')
) {
return NULL;
}
if (label_sz == 3 && name[idx - 1] == '-') {
if (strncasecmp(&(name[idx - 3]), "xn", 2) != 0) {
// label[2..=3] is "--", but label[0..=1] isn't "xn"
return NULL;
} else {
assert(label_type == nr_ldh);
label_type = a;
}
}
} else if (name[idx] < '0' || name[idx] > '9') {
if ((name[idx] | 0x20) >= 'a' && (name[idx] | 0x20) <= 'z') {
name_contains_alphabetic_character = true;
} else {
// u-labels are unsupported
return NULL;
}
}
label_sz += 1;
}
if (!name_contains_alphabetic_character) {
return NULL;
}
success:;
*name_sz = sz;
return name;
}
static struct bdd_name_desc *wlock_name_desc(struct hashmap_key *key/*, bool *created*/) {
assert(key != NULL/* && created != NULL*/);
struct bdd_name_desc *expected = NULL;
enum hashmap_cas_result r;
r = hashmap_cas(
HASHMAP, AREA, key,
(void **)&(expected), NULL,
hashmap_cas_get, (void *)0
);
if (r == hashmap_cas_again) {
//*created = false;
return expected;
}
struct bdd_name_desc *name_desc = alloc_name_desc();
if (name_desc == NULL) {
return NULL;
}
pthread_rwlock_wrlock(&(name_desc->rwlock));
// works because only the command thread (this thread) can mutate HASHMAP
r = hashmap_cas(
HASHMAP, AREA, key,
(void **)&(expected), name_desc,
hashmap_cas_set, NULL
);
if (r != hashmap_cas_success) {
pthread_rwlock_unlock(&(name_desc->rwlock));
free_name_desc(name_desc);
return NULL;
}
//*created = true;
return name_desc;
}
// exposed function
// bdd_name_descs_add_service_instance **cannot** replace a service instance.
// it may only add service instances.
bool bdd_name_descs_add_service_instance(
const char *scope,
size_t scope_sz,
const struct bdd_service *service,
const void *instance_info
) {
// normalize scope
scope = bdd_name(scope, &(scope_sz));
if (scope == NULL) {
return false;
}
struct bdd_service_instance *service_inst = malloc(sizeof(struct bdd_service_instance));
if (service_inst == NULL) {
return false;
}
service_inst->service = service;
service_inst->instance_info = instance_info;
service_inst->next = NULL;
struct hashmap_key key;
hashmap_key((void *)scope, scope_sz, &(key));
struct bdd_name_desc *name_desc = wlock_name_desc(&(key));
if (name_desc == NULL) {
err:;
free(service_inst);
return false;
}
bool success = add_service_inst(name_desc, service_inst);
pthread_rwlock_unlock(&(name_desc->rwlock));
if (!success) {
goto err;
}
return true;
}
// internal function
// cannot be called concurrently
static bool hashmap_set_cert_pkey(
const char *scope,
size_t scope_sz,
X509 *x509,
EVP_PKEY *pkey
) {
// normalize scope
scope = bdd_name(scope, &(scope_sz));
if (scope == NULL) {
return false;
}
// create or retrieve the name's description
struct hashmap_key key;
hashmap_key((void *)scope, scope_sz, &(key));
struct bdd_name_desc *name_desc = wlock_name_desc(&(key));
if (name_desc == NULL) {
return false;
}
// set its certificate and private key
set_cert_pkey(name_desc, x509, pkey);
pthread_rwlock_unlock(&(name_desc->rwlock));
return true;
}
// exposed function
// cannot be called concurrently
void bdd_name_descs_use_cert_pkey(
X509 *x509,
EVP_PKEY *pkey
) {
// to-do: support for (owned/reserved) ip addresses?
#define update() \
if (hashmap_set_cert_pkey( \
(const char *)asn1_str->data, \
asn1_str->length, \
x509, \
pkey \
)) { \
printf("updated %.*s\n", asn1_str->length, asn1_str->data); \
X509_up_ref(x509); \
EVP_PKEY_up_ref(pkey); \
}
GENERAL_NAMES *dns_alt_names = X509_get_ext_d2i(x509, NID_subject_alt_name, 0, 0);
X509_NAME *dns_subject_names = X509_get_subject_name(x509);
if (dns_alt_names != NULL) {
int n_dns_alt_names = sk_GENERAL_NAME_num(dns_alt_names);
for (int idx = 0; idx < n_dns_alt_names; ++idx) {
GENERAL_NAME *entry = sk_GENERAL_NAME_value(dns_alt_names, idx);
if (entry->type != GEN_DNS) {
continue;
}
ASN1_IA5STRING *asn1_str = entry->d.dNSName;
update();
}
GENERAL_NAMES_free(dns_alt_names);
} else if (dns_subject_names != NULL) {
int n_dns_subject_names = X509_NAME_entry_count(dns_subject_names);
for (int idx = 0; idx < n_dns_subject_names; ++idx) {
X509_NAME_ENTRY *entry = X509_NAME_get_entry(dns_subject_names, idx);
ASN1_OBJECT *asn1_obj = X509_NAME_ENTRY_get_object(entry);
ASN1_STRING *asn1_str = X509_NAME_ENTRY_get_data(entry);
if (
asn1_obj == NULL || asn1_str == NULL ||
OBJ_obj2nid(asn1_obj) != NID_commonName
) {
continue;
}
update();
}
}
return;
}
static void acq(struct bdd_name_desc *name_desc, enum hashmap_callback_reason reason, uintptr_t md) {
assert(name_desc != NULL && md <= 1);
static_assert(sizeof(uintptr_t) >= sizeof(char) /* 1 */, "what");
switch (reason) {
case (hashmap_acquire): {
if (md == 0) {
pthread_rwlock_wrlock(&(name_desc->rwlock));
} else {
pthread_rwlock_rdlock(&(name_desc->rwlock));
}
break;
}
case (hashmap_drop_destroy): {
free_name_desc(name_desc);
break;
}
default: abort();
}
return;
}
bool bdd_name_descs_create(uint16_t n_threads) {
HASHMAP = hashmap_create(n_threads, 64, 0.94, 2, (hashmap_callback)acq);
if (HASHMAP != NULL) {
AREA = hashmap_area(bdd_gv.name_descs);
return true;
}
return false;
}
void bdd_name_descs_destroy(void) {
if (HASHMAP != NULL) {
hashmap_area_release(HASHMAP, AREA);
hashmap_destroy(HASHMAP);
}
return;
}

View File

@ -92,7 +92,10 @@ void *bdd_serve(struct bdd_worker_data *worker_data) {
}
switch (conversation->state) {
case (bdd_conversation_accept): {
if (bdd_accept_continue(conversation) == bdd_cont_conversation_discard) {
worker_data->ssl_cb_ctx.conversation = conversation;
worker_data->ssl_cb_ctx.protocol_name =
(void *)(worker_data->ssl_cb_ctx.cstr_protocol_name = NULL);
if (bdd_accept_continue(&(worker_data->ssl_cb_ctx)) == bdd_cont_conversation_discard) {
if (conversation->n_ev >= 1) {
process_unlink(&(process_list), conversation);
}

View File

@ -10,14 +10,15 @@ gcc = [
"-o", os.path.join(file_dirname, "output", "bidirectiond"),
"-I" + os.path.join(file_dirname, "inc")
"-I" + os.path.join(file_dirname, "bdd", "headers"),
"-I" + os.path.join(file_dirname, "hashmap", "src"),
]
for directory, _, files in os.walk(os.path.join(file_dirname, "bidirectiond")):
for directory, _, files in os.walk(os.path.join(file_dirname, "cmd")):
for file_name in files:
if file_name[-2:] != ".c":
continue
gcc.append(os.path.join(directory, file_name))
for directory, _, files in os.walk(os.path.join(file_dirname, "core")):
for directory, _, files in os.walk(os.path.join(file_dirname, "bdd")):
for file_name in files:
if file_name[-2:] != ".c":
continue

View File

@ -1,7 +1,7 @@
#ifndef bidirectiond__core_settings__h
#define bidirectiond__core_settings__h
#include <bdd-core/settings.h>
#include <settings.h>
extern const struct bdd_service services[];
extern struct bdd_settings settings;

View File

@ -112,44 +112,44 @@ void input_processor(int sfd, char *br_buf, int br_buf_sz) {
bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
for (;;) {
if (!buffered_read()) {
e |= 0b1;
goto tls_pem_load_err;
goto tls_pem_load_out;
}
if (br_ctx.byte == 0) {
break;
}
if (br_ctx.byte == 1 || BIO_write(bio, &(br_ctx.byte), 1) != 1) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
}
// deserialize the certificate
x509 = PEM_read_bio_X509(bio, NULL, NULL, "");
if (x509 == NULL) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
BIO_free(bio);
bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
for (;;) {
if (!buffered_read()) {
e |= 0b1;
goto tls_pem_load_err;
goto tls_pem_load_out;
}
if (br_ctx.byte == 0) {
break;
}
if (br_ctx.byte == 1 || BIO_write(bio, &(br_ctx.byte), 1) != 1) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
}
@ -165,7 +165,7 @@ void input_processor(int sfd, char *br_buf, int br_buf_sz) {
char env_variable_name[0x100];
for (size_t idx = 0;; ++idx) {
if (idx == sizeof(env_variable_name)) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
env_variable_name[idx] = br_ctx.byte;
if (br_ctx.byte == 0) {
@ -173,11 +173,11 @@ void input_processor(int sfd, char *br_buf, int br_buf_sz) {
break;
}
if (br_ctx.byte == 1) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
if (!buffered_read()) {
e |= 0b1;
goto tls_pem_load_err;
goto tls_pem_load_out;
}
}
}
@ -185,14 +185,12 @@ void input_processor(int sfd, char *br_buf, int br_buf_sz) {
// deserialize the private key
pkey = PEM_read_bio_PrivateKey(bio, NULL, cp_pwd, &(cp_ctx));
if (pkey == NULL) {
goto tls_pem_load_err;
goto tls_pem_load_out;
}
if (bdd_name_descs_use_cert_pkey(settings.name_descs, &(x509), &(pkey))) {
e |= 0b10;
}
bdd_name_descs_use_cert_pkey(x509, pkey);
tls_pem_load_err:;
tls_pem_load_out:;
if (bio != NULL) {
BIO_free(bio);
}
@ -202,11 +200,7 @@ void input_processor(int sfd, char *br_buf, int br_buf_sz) {
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
if (e & 0b10) {
puts("added SSL_CTX");
} else {
puts("failed to add SSL_CTX");
}
if (e & 0b1) {
goto err;
}

View File

@ -1,7 +1,7 @@
#include <poll.h>
#include <assert.h>
#include <arpa/inet.h>
#include <bdd-core/settings.h>
#include <settings.h>
#include <fcntl.h>
#include <openssl/engine.h>
#include <openssl/err.h>
@ -28,10 +28,8 @@
#endif
struct bdd_settings settings = {
.name_descs = NULL,
.n_conversations = 0x100,
.n_epoll_oevents = 0x200,
.n_worker_threads = 16,
.epoll_timeout = -1,
.sockfds = NULL,
};
@ -76,7 +74,6 @@ int main(int argc, char *argv[], char *env[]) {
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
bool bdd_instance;
@ -89,9 +86,11 @@ int main(int argc, char *argv[], char *env[]) {
};
int sig_fd = -1;
size_t n_threads = sysconf(_SC_NPROCESSORS_ONLN) /* workers */;
// name_descs
if ((settings.name_descs = bdd_name_descs_create()) == NULL) {
fputs("failed to allocate settings.name_descs\n", stderr);
if (!bdd_name_descs_create(n_threads + 1)) {
fputs("failed to allocate name_descs\n", stderr);
goto clean_up;
}
// args
@ -145,11 +144,7 @@ int main(int argc, char *argv[], char *env[]) {
}
arg_iter:;
while ((*arg) != NULL) {
if (strcmp((*arg), "--n-worker-threads") == 0 || strcmp((*arg), "-t") == 0) {
EXPECT_ARGS(1);
EXPECT(stousi(&(settings.n_worker_threads), arg[1]));
arg += 2;
} else if (strcmp((*arg), "-l") == 0) {
if (strcmp((*arg), "-l") == 0) {
EXPECT_ARGS(2);
struct rlimit rlimit;
EXPECT(storlim(&(rlimit.rlim_cur), arg[1]));
@ -185,6 +180,7 @@ int main(int argc, char *argv[], char *env[]) {
sigaction(SIGHUP, &(action), 0);
arg += 1;
} else if (strcmp((*arg), "--tls-credentials") == 0 || strcmp((*arg), "-c") == 0) {
// to-do: support omission of 3rd argument
EXPECT_ARGS(3);
X509 *x509 = NULL;
EVP_PKEY *pkey = NULL;
@ -194,7 +190,7 @@ int main(int argc, char *argv[], char *env[]) {
FILE *file = fopen(arg[1], "r");
if (file == NULL) {
fprintf(stderr, "couldn't access certificate file (%s)\n", arg[1]);
goto arg_creds_err;
goto arg_creds_out;
}
x509 = PEM_read_X509(file, NULL, NULL, NULL);
@ -202,7 +198,7 @@ int main(int argc, char *argv[], char *env[]) {
if (x509 == NULL) {
fprintf(stderr, "invalid certificate file (%s)\n", arg[1]);
goto arg_creds_err;
goto arg_creds_out;
}
// read private key //
@ -215,7 +211,7 @@ int main(int argc, char *argv[], char *env[]) {
file = fopen(arg[2], "r");
if (file == NULL) {
fprintf(stderr, "couldn't access private key file (%s)\n", arg[1]);
goto arg_creds_err;
goto arg_creds_out;
}
pkey = PEM_read_PrivateKey(file, NULL, &(cp_pwd), &(cp_ctx));
@ -223,19 +219,15 @@ int main(int argc, char *argv[], char *env[]) {
if (pkey == NULL) {
fprintf(stderr, "invalid private key file (%s)\n", arg[2]);
goto arg_creds_err;
goto arg_creds_out;
}
if (!cp_ctx.success) {
fputs("the private key file must be encrypted\n", stderr);
goto arg_creds_err;
fputs("the private key file should be encrypted\n", stderr);
}
if (!bdd_name_descs_use_cert_pkey(settings.name_descs, &(x509), &(pkey))) {
fputs("seemingly invalid certificate file\n", stderr);
goto arg_creds_err;
}
bdd_name_descs_use_cert_pkey(x509, pkey);
arg_creds_err:;
arg_creds_out:;
if (x509 != NULL) {
X509_free(x509);
}
@ -285,7 +277,6 @@ int main(int argc, char *argv[], char *env[]) {
n += 1;
}
if (!services[idx].instantiate(
settings.name_descs,
&(services[idx]),
n,
(const char **)arg
@ -299,7 +290,6 @@ int main(int argc, char *argv[], char *env[]) {
}
arg_err:;
fputs("argument parsing failed\n"
"-t: set the amount of worker threads\n"
"--epoll-timeout: set the timeout (in ms) for "
"bdd_conversation structs\n"
"-l: set the rlimits for open files (soft limit, "
@ -353,11 +343,11 @@ int main(int argc, char *argv[], char *env[]) {
sv_addr.inet6.sin6_port = htons(port);
}
// try to bind to port
sockfds = malloc(sizeof(int) * settings.n_worker_threads);
sockfds = malloc(sizeof(int) * n_threads);
if (sockfds == NULL) {
goto clean_up;
}
for (; fuck_idx < settings.n_worker_threads; ++fuck_idx) {
for (; fuck_idx < n_threads; ++fuck_idx) {
int fd = socket(af, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd < 0) {
fprintf(stderr, "failed to create sv_socket! errno: %i\n", errno);
@ -496,9 +486,7 @@ int main(int argc, char *argv[], char *env[]) {
free(sockfds);
}
// aight
if (settings.name_descs != NULL) {
bdd_name_descs_destroy(&(settings.name_descs));
}
bdd_name_descs_destroy();
// https://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
// FIPS_mode_set(0);
CRYPTO_set_locking_callback(NULL);

1
compile_flags.txt Normal file
View File

@ -0,0 +1 @@
-I./hashmap/src

@ -1 +0,0 @@
Subproject commit 3bfff93ccd5e7f19e604b578b9e647bf0a995516

View File

@ -1,26 +0,0 @@
#ifndef bidirectiond_core__settings__h
#define bidirectiond_core__settings__h
#include <openssl/ssl.h>
#include <stdbool.h>
#include "../src/headers/bdd_name_descs.h"
#include "../src/headers/bdd_settings.h"
#include "../src/headers/bdd_service.h"
#include "../src/headers/bdd_stop.h"
struct bdd_name_descs;
struct bdd_instance *bdd_go(struct bdd_settings settings);
void bdd_wait(void);
void bdd_destroy(void);
bool bdd_name_descs_use_cert_pkey(
struct bdd_name_descs *name_descriptions,
X509 **x509_ref,
EVP_PKEY **pkey_ref
);
struct bdd_name_descs *bdd_name_descs_create(void);
void bdd_name_descs_destroy(struct bdd_name_descs **name_descs);
#endif

View File

@ -1,6 +0,0 @@
#ifndef bidirectiond_core__bdd_name_descs__h
#define bidirectiond_core__bdd_name_descs__h
struct bdd_name_descs;
#endif

View File

@ -1,6 +0,0 @@
#ifndef bidirectiond_core__bdd_stop__h
#define bidirectiond_core__bdd_stop__h
void bdd_stop(void);
#endif

View File

@ -1,17 +0,0 @@
#ifndef bidirectiond_core__serve__h
#define bidirectiond_core__serve__h
#include <sys/epoll.h>
#include "timeout_list.h"
struct bdd_worker_data {
int epoll_fd;
int serve_fd;
SSL_CTX *ssl_ctx;
struct bdd_tl timeout_list;
struct epoll_event events[];
};
void *bdd_serve(struct bdd_worker_data *worker_data);
#endif

View File

@ -1,296 +0,0 @@
#include <stdbool.h>
#include <stddef.h>
#include <hashmap/hashmap.h>
#include <openssl/x509v3.h>
#include <string.h>
#include "headers/name_descs.h"
#include "headers/bdd_name_descs.h"
#include "headers/bdd_service.h"
// struct bdd_name_desc
struct bdd_name_desc *bdd_name_desc_alloc(void) {
struct bdd_name_desc *name_desc = malloc(sizeof(struct bdd_name_desc));
if (name_desc == NULL) {
return NULL;
}
name_desc->x509 = NULL;
name_desc->pkey = NULL;
name_desc->service_instances = NULL;
return name_desc;
}
void bdd_name_desc_clean_cert_pkey(struct bdd_name_desc *name_desc) {
if (name_desc->x509 != NULL) {
// misleading function name; it actually
// decs the ref count and frees the shit
// if the rc hits 0
X509_free(name_desc->x509);
EVP_PKEY_free(name_desc->pkey);
name_desc->x509 = NULL;
name_desc->pkey = NULL;
}
return;
}
void bdd_name_desc_clean_services(struct bdd_name_desc *name_desc) {
for (
struct bdd_service_instance **service_inst = &(name_desc->service_instances);
(*service_inst) != NULL;
) {
struct bdd_service_instance *curr = (*service_inst);
(*service_inst) = curr->next;
if (curr->instance_info != NULL) {
curr->service->instance_info_destructor((void *)curr->instance_info);
}
free(curr);
}
return;
}
bool bdd_name_desc_add_service_instance(
struct bdd_name_desc *name_desc,
struct bdd_service_instance *service_inst
) {
struct bdd_service_instance **curr = &(name_desc->service_instances);
const char *const *inst_sp = service_inst->service->supported_protocols;
for (; (*curr) != NULL; curr = &((*curr)->next)) {
const char *const *curr_sp = (*curr)->service->supported_protocols;
if (inst_sp == NULL || curr_sp == NULL) {
if (inst_sp == curr_sp) {
return false;
}
continue;
}
for (size_t idx = 0; curr_sp[idx]; ++idx) {
for (size_t idx2 = 0; inst_sp[idx2]; ++idx2) {
if (strcmp(curr_sp[idx], inst_sp[idx2]) == 0) {
return false;
}
}
}
}
(*curr) = service_inst;
return true;
}
void bdd_name_desc_set_cert_pkey(struct bdd_name_desc *name_desc, X509 *x509, EVP_PKEY *pkey) {
bdd_name_desc_clean_cert_pkey(name_desc);
name_desc->x509 = x509;
name_desc->pkey = pkey;
return;
}
void bdd_name_desc_destroy(struct bdd_name_desc *name_desc) {
bdd_name_desc_clean_services(name_desc);
bdd_name_desc_clean_cert_pkey(name_desc);
free(name_desc);
return;
}
void bdd_name_desc_destroy_hm(struct bdd_name_desc *name_desc, enum hashmap_drop_mode _) {
bdd_name_desc_destroy(name_desc);
return;
}
// name_descs hashmap
void bdd_name_trim(const unsigned char *name, size_t *name_sz) {
if ((*name_sz) >= 1 && name[(*name_sz) - 1] == '.') { \
(*name_sz) -= 1;
}
return;
}
#define bdd_name_descs_prelude() \
bool r = false; \
struct hashmap *name_descs = (struct hashmap *)bdd_name_descs; \
bdd_name_trim(scope, &(scope_sz)); \
if (scope_sz > 0 && scope[0] == '*') { \
if (scope_sz > 1 && scope[1] != '.') { \
return false; \
} \
scope += 1; \
scope_sz -= 1; \
} \
struct hashmap_key key = HASHMAP_KEY_INITIALIZER; \
hashmap_key_obtain(name_descs, &(key), scope, scope_sz); \
struct bdd_name_desc *name_desc; \
bool created_name_desc; \
if (!hashmap_get(name_descs, &(key), (void *)&(name_desc))) { \
if ((name_desc = bdd_name_desc_alloc()) == NULL) { \
goto out; \
} \
created_name_desc = true; \
} else { \
created_name_desc = false; \
}
#define bdd_name_descs_out() \
out:; \
hashmap_key_release(name_descs, &(key), false); \
return r;
// exposed function
// bdd_name_descs_add_service_instance **cannot** replace a service instance;
// it may only add service instances.
bool bdd_name_descs_add_service_instance(
struct bdd_name_descs *bdd_name_descs,
const unsigned char *scope,
size_t scope_sz,
const struct bdd_service *service,
const void **instance_info
) {
bdd_name_descs_prelude();
struct bdd_service_instance *service_inst = malloc(sizeof(struct bdd_service_instance));
if (service_inst == NULL) {
goto out;
}
service_inst->service = service;
service_inst->next = NULL;
if (!bdd_name_desc_add_service_instance(name_desc, service_inst)) {
if (created_name_desc) {
bdd_name_desc_destroy(name_desc);
}
free(service_inst);
goto out;
}
if (created_name_desc) {
if (!hashmap_set(name_descs, &(key), name_desc)) {
// will free service_inst
bdd_name_desc_destroy(name_desc);
goto out;
}
}
service_inst->instance_info = *instance_info;
*instance_info = NULL;
r = true;
goto out;
bdd_name_descs_out();
}
// internal function
bool bdd_name_descs_set_cert_pkey(
struct bdd_name_descs *bdd_name_descs,
const unsigned char *scope,
size_t scope_sz,
X509 *x509,
EVP_PKEY *pkey
) {
bdd_name_descs_prelude();
bdd_name_desc_set_cert_pkey(name_desc, x509, pkey);
if (created_name_desc) {
if (!hashmap_set(name_descs, &(key), name_desc)) {
bdd_name_desc_destroy(name_desc);
goto out;
}
}
r = true;
goto out;
bdd_name_descs_out();
}
// exposed function
bool bdd_name_descs_use_cert_pkey(
struct bdd_name_descs *bdd_name_descs,
X509 **x509_ref,
EVP_PKEY **pkey_ref
) {
X509 *x509 = *x509_ref;
EVP_PKEY *pkey = *pkey_ref;
bool should_up_rc = false;
GENERAL_NAMES *dns_alt_names = X509_get_ext_d2i(x509, NID_subject_alt_name, 0, 0);
if (dns_alt_names != NULL) {
int n_dns_alt_names = sk_GENERAL_NAME_num(dns_alt_names);
if (n_dns_alt_names < 0) {
n_dns_alt_names = 0;
}
for (int idx = 0; idx < n_dns_alt_names; ++idx) {
GENERAL_NAME *entry = sk_GENERAL_NAME_value(dns_alt_names, idx);
if (entry->type != GEN_DNS) {
continue;
}
ASN1_IA5STRING *asn1_str = entry->d.dNSName;
int data_length = asn1_str->length;
bool s = bdd_name_descs_set_cert_pkey(
bdd_name_descs,
(const unsigned char *)asn1_str->data,
data_length,
x509,
pkey
);
if (s) {
if (should_up_rc) {
X509_up_ref(x509);
EVP_PKEY_up_ref(pkey);
} else {
should_up_rc = true;
}
}
}
GENERAL_NAMES_free(dns_alt_names);
} else { // rfc6125
X509_NAME *dns_subject_names = X509_get_subject_name(x509);
if (dns_subject_names != NULL) {
int n_dns_subject_names = X509_NAME_entry_count(dns_subject_names);
if (n_dns_subject_names < 0) {
n_dns_subject_names = 0;
}
for (int idx = 0; idx < n_dns_subject_names; ++idx) {
X509_NAME_ENTRY *entry = X509_NAME_get_entry(dns_subject_names, idx);
ASN1_OBJECT *asn1_obj = X509_NAME_ENTRY_get_object(entry);
ASN1_STRING *asn1_str = X509_NAME_ENTRY_get_data(entry);
if (asn1_obj == NULL || asn1_str == NULL) {
continue;
}
if (OBJ_obj2nid(asn1_obj) != NID_commonName) {
continue;
}
int data_length = asn1_str->length;
bool s = bdd_name_descs_set_cert_pkey(
bdd_name_descs,
(const unsigned char *)asn1_str->data,
data_length,
x509,
pkey
);
if (s) {
if (should_up_rc) {
X509_up_ref(x509);
EVP_PKEY_up_ref(pkey);
} else {
should_up_rc = true;
}
}
}
}
}
if (!should_up_rc) {
// x509 and pkey's ref counts will be the same as
// they were before this function was called
return false;
}
// invalidate some pointers
*x509_ref = NULL;
*pkey_ref = NULL;
return true;
}
struct bdd_name_descs *bdd_name_descs_create(void) {
return (struct bdd_name_descs *)hashmap_create(183, 16, (void *)&(bdd_name_desc_destroy_hm));
}
void bdd_name_descs_destroy(struct bdd_name_descs **name_descs) {
hashmap_destroy_ref((struct hashmap **)name_descs);
return;
}

1
hashmap Submodule

@ -0,0 +1 @@
Subproject commit 8ff5db70a63331b7e8d4264c50d8a4dbd32cfef3

View File

@ -1 +0,0 @@
../core/headers

View File

@ -1 +0,0 @@
../core/hashmap/headers/

View File

@ -35,7 +35,7 @@ def append_service(service):
value = service[key]
if type(value) != str:
raise Exception("error")
declarations += f"bool {value}(struct bdd_name_descs *name_descs, const struct bdd_service *service, size_t n_arguments, const char **arguments);"
declarations += f"bool {value}(const struct bdd_service *service, size_t n_arguments, const char **arguments);"
service_str += f".{key} = &({value}),"
#
key = "handle_events"
@ -90,7 +90,7 @@ for path in glob.glob(os.path.join(dir_path, "*/service.json")):
services += "};const size_t n_services = " + str(n_services) + ";"
fd = tempfile.NamedTemporaryFile(delete=False, suffix=".c")
fd.write(b"#include <bdd-core/settings.h>\n" + bytes(declarations, "ascii") + bytes(services, "ascii"))
fd.write(b"#include <settings.h>\n" + bytes(declarations, "ascii") + bytes(services, "ascii"))
fd.close()
subprocess.run([
"gcc",
@ -98,6 +98,6 @@ subprocess.run([
"-c", fd.name,
"-o", os.path.join(dir_path, "..", "output", "glue.o"),
"-I" + os.path.join(dir_path, "..", "inc"),
"-I" + os.path.join(dir_path, "..", "bdd", "headers"),
])
os.unlink(fd.name)

View File

@ -1,4 +1,4 @@
#include <bdd-core/services.h>
#include "../../bdd/headers/services.h"
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
@ -127,7 +127,7 @@ bool general_service__conversation_init(
if (a == NULL) {
return false;
}
bdd_set_associated(conversation, a, NULL);
bdd_set_associated(conversation, a, free);
return true;
}
}
@ -144,7 +144,6 @@ void general_service__instance_info_destructor(void *hint) {
return;
}
static bool handle_s(
struct bdd_name_descs *name_descriptions,
const struct bdd_service *service,
const char *scope,
const char *addr,
@ -174,17 +173,15 @@ static bool handle_s(
info->addrinfo = res;
res = NULL;
if (!bdd_name_descs_add_service_instance(name_descriptions, scope, strlen(scope), service, (void *)&(info))) {
goto err;
if (bdd_name_descs_add_service_instance(scope, strlen(scope), service, (void *)info)) {
return true;
}
return true;
err:;
general_service__instance_info_destructor(info);
return false;
}
bool general_service__instantiate(
struct bdd_name_descs *name_descriptions,
const struct bdd_service *service,
size_t argc,
const char **argv
@ -201,7 +198,7 @@ bool general_service__instantiate(
} else {
return false;
}
return handle_s(name_descriptions, service, argv[1], argv[2], argv[3], use_tls);
return handle_s(service, argv[1], argv[2], argv[3], use_tls);
}
return false;
}