summaryrefslogtreecommitdiff
path: root/src/irmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/irmd')
-rw-r--r--src/irmd/CMakeLists.txt33
-rw-r--r--src/irmd/config.h.in57
-rw-r--r--src/irmd/configfile.c332
-rw-r--r--src/irmd/ipcp.c39
-rw-r--r--src/irmd/irmd.h2
-rw-r--r--src/irmd/main.c978
-rw-r--r--src/irmd/oap.c288
-rw-r--r--src/irmd/oap.h94
-rw-r--r--src/irmd/reg/flow.h12
-rw-r--r--src/irmd/reg/ipcp.c8
-rw-r--r--src/irmd/reg/name.c74
-rw-r--r--src/irmd/reg/name.h28
-rw-r--r--src/irmd/reg/proc.h4
-rw-r--r--src/irmd/reg/reg.c289
-rw-r--r--src/irmd/reg/reg.h24
-rw-r--r--src/irmd/reg/tests/CMakeLists.txt6
-rw-r--r--src/irmd/reg/tests/flow_test.c40
-rw-r--r--src/irmd/reg/tests/ipcp_test.c9
-rw-r--r--src/irmd/reg/tests/name_test.c94
-rw-r--r--src/irmd/reg/tests/proc_test.c25
-rw-r--r--src/irmd/reg/tests/prog_test.c22
-rw-r--r--src/irmd/reg/tests/reg_test.c495
-rw-r--r--src/irmd/tests/CMakeLists.txt10
-rw-r--r--src/irmd/tests/irm_test.c33
-rw-r--r--src/irmd/tests/oap_test.c285
25 files changed, 2518 insertions, 763 deletions
diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt
index c9c2e553..46d49391 100644
--- a/src/irmd/CMakeLists.txt
+++ b/src/irmd/CMakeLists.txt
@@ -4,13 +4,14 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR}/include)
+set(OUROBOROS_CONFIG_DIR /etc/ouroboros CACHE STRING
+ "Configuration directory")
+
find_library(LIBTOML_LIBRARIES toml QUIET)
if (LIBTOML_LIBRARIES)
set(DISABLE_CONFIGFILE FALSE CACHE BOOL
"Disable configuration file support")
if (NOT DISABLE_CONFIGFILE)
- set(OUROBOROS_CONFIG_DIR /etc/ouroboros/ CACHE STRING
- "Configuration directory")
set(OUROBOROS_CONFIG_FILE irmd.conf CACHE STRING
"Name of the IRMd configuration file")
set(HAVE_TOML TRUE)
@@ -23,11 +24,11 @@ if (LIBTOML_LIBRARIES)
install(FILES "${CMAKE_BINARY_DIR}/irmd.conf.example"
DESTINATION "${OUROBOROS_CONFIG_DIR}")
unset(INSTALL_DIR)
- mark_as_advanced(LIBTOML_LIBRARIES)
+ find_path(LIBTOML_INCLUDE toml.h)
+ mark_as_advanced(LIBTOML_LIBRARIES LIBTOML_INCLUDE)
else ()
message(STATUS "Configuration file support disabled by user")
unset(OUROBOROS_CONFIG_FILE CACHE)
- unset(OUROBOROS_CONFIG_DIR CACHE)
set(HAVE_TOML FALSE)
endif ()
else ()
@@ -38,16 +39,26 @@ else ()
unset(HAVE_TOML)
endif ()
+set(OUROBOROS_SECURITY_DIR "${OUROBOROS_CONFIG_DIR}/security" CACHE STRING
+ "Security directory holding authentication information")
+set(OUROBOROS_CA_CRT_DIR "${OUROBOROS_SECURITY_DIR}/cacert" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_SRV_CRT_DIR "${OUROBOROS_SECURITY_DIR}/server" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_CLI_CRT_DIR "${OUROBOROS_SECURITY_DIR}/client" CACHE STRING
+ "Directory holding trusted CA certificates")
+set(OUROBOROS_UNTRUSTED_DIR "${OUROBOROS_SECURITY_DIR}/untrusted" CACHE STRING
+ "Directory holding untrusted intermediate certificates")
+
set(IRMD_REQ_ARR_TIMEOUT 1000 CACHE STRING
"Timeout for an application to respond to a new flow (ms)")
-
set(BOOTSTRAP_TIMEOUT 5000 CACHE STRING
"Timeout for an IPCP to bootstrap (ms)")
set(ENROLL_TIMEOUT 20000 CACHE STRING
"Timeout for an IPCP to enroll (ms)")
set(REG_TIMEOUT 20000 CACHE STRING
"Timeout for registering a name (ms)")
-set(QUERY_TIMEOUT 20000 CACHE STRING
+set(QUERY_TIMEOUT 200 CACHE STRING
"Timeout to query a name with an IPCP (ms)")
set(CONNECT_TIMEOUT 20000 CACHE STRING
"Timeout to connect an IPCP to another IPCP (ms)")
@@ -61,6 +72,8 @@ set(IRMD_PKILL_TIMEOUT 30 CACHE STRING
"Number of seconds to wait before sending SIGKILL to subprocesses on exit")
set(IRMD_KILL_ALL_PROCESSES TRUE CACHE BOOL
"Kill all processes on exit")
+set(DEBUG_PROTO_OAP FALSE CACHE BOOL
+ "Add Flow allocation protocol message output to IRMd debug logging")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
@@ -70,6 +83,7 @@ set(SOURCE_FILES
ipcp.c
configfile.c
main.c
+ oap.c
reg/flow.c
reg/ipcp.c
reg/proc.c
@@ -83,6 +97,10 @@ add_executable (irmd ${SOURCE_FILES})
target_link_libraries (irmd LINK_PUBLIC ouroboros-common
${LIBTOML_LIBRARIES})
+if (HAVE_TOML)
+ target_include_directories(irmd PUBLIC ${LIBTOML_INCLUDE})
+endif ()
+
include(AddCompileFlags)
if (CMAKE_BUILD_TYPE MATCHES "Debug*")
add_compile_flags(irmd -DCONFIG_OUROBOROS_DEBUG)
@@ -90,6 +108,5 @@ endif ()
install(TARGETS irmd RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR})
-# Enable once irmd has tests
-#add_subdirectory(tests)
add_subdirectory(reg)
+add_subdirectory(tests)
diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in
index fa1156b9..527694c0 100644
--- a/src/irmd/config.h.in
+++ b/src/irmd/config.h.in
@@ -21,7 +21,8 @@
*/
-#define IPCP_UDP_EXEC "@IPCP_UDP_TARGET@"
+#define IPCP_UDP4_EXEC "@IPCP_UDP4_TARGET@"
+#define IPCP_UDP6_EXEC "@IPCP_UDP6_TARGET@"
#define IPCP_ETH_LLC_EXEC "@IPCP_ETH_LLC_TARGET@"
#define IPCP_ETH_DIX_EXEC "@IPCP_ETH_DIX_TARGET@"
#define IPCP_UNICAST_EXEC "@IPCP_UNICAST_TARGET@"
@@ -50,7 +51,6 @@
#define IRMD_MIN_THREADS @IRMD_MIN_THREADS@
#define IRMD_ADD_THREADS @IRMD_ADD_THREADS@
-
#cmakedefine HAVE_FUSE
#ifdef HAVE_FUSE
#define FUSE_PREFIX "@FUSE_PREFIX@"
@@ -62,36 +62,33 @@
#define OUROBOROS_CONFIG_FILE "@OUROBOROS_CONFIG_FILE@"
#endif
+#define OUROBOROS_SECURITY_DIR "@OUROBOROS_SECURITY_DIR@"
+#define OUROBOROS_CA_CRT_DIR "@OUROBOROS_CA_CRT_DIR@"
+#define OUROBOROS_SRV_CRT_DIR "@OUROBOROS_SRV_CRT_DIR@"
+#define OUROBOROS_CLI_CRT_DIR "@OUROBOROS_CLI_CRT_DIR@"
+#define OUROBOROS_CHAIN_DIR "@OUROBOROS_UNTRUSTED_DIR@"
+
#define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@
#cmakedefine IRMD_KILL_ALL_PROCESSES
#cmakedefine HAVE_LIBGCRYPT
+#cmakedefine HAVE_OPENSSL
+#ifdef CONFIG_OUROBOROS_DEBUG
+#cmakedefine DEBUG_PROTO_OAP
+#endif
+
+#define _B ""
+#define _G ""
+#define RST ""
-#define O7S_ASCII_ART \
-"\n" \
-" ▄▄█████▄▄▄\n" \
-" ▄█▀▀ ▀▀███▄ " \
-"█\n" \
-" ██ ▄▄▄ ▄███▄ " \
-"▄ ▄ ▄ ▄▄" \
-" ▄▄ █ ▄▄ " \
-" ▄▄ ▄ ▄▄ " \
-"▄▄ ▄▄\n" \
-" ██ █ █ " \
-"[38;5;4m█████ █ █ " \
-"█▀ ▀ █ █" \
-" █▀ █ █ " \
-"█ █▀ ▀ █" \
-" █ ▀▄ ▀\n" \
-" ██ ▀▄▄▄▀ ▀█▀ " \
-"█ █ █ " \
-"█ █ █▄ █ " \
-"█ █ █ █" \
-" █ ▄ ▀▄\n" \
-" █▄ █ ▀▀▀" \
-" ▀ ▀ ▀▀" \
-" ▀ ▀▀ ▀▀ " \
-"▀ ▀▀ ▀▀\n" \
-" ▀█▄▄▄▄▄▄▄▄▀\n" \
-" ▀▀▀▀▀▀\n" \
-"\n"
+#define O7S_ASCII_ART \
+RST "\n" \
+_B " ▄▄█████▄▄▄ \n" \
+_B " ▄█▀▀ ▀▀███▄ " _G " █ \n" \
+_B " ██ ▄▄▄ ▄███▄ " _G "▄ ▄ ▄ ▄ ▄▄ █▄▄ ▄▄ ▄ ▄ ▄▄ ▄▄ \n" \
+_B " ██ █ █ █████ " _G "█ █ █▀ ▀ █ █ █ █ █ █ █▀ ▀ █ █ ▀▄ ▀\n" \
+_B " ██ ▀▄▄▄▀ ▀█▀ " _G "█ █ █ █ █ █ █ █ █ █ █ █ ▄ ▀▄\n" \
+_B " █▄ █ " _G " ▀▀ ▀ ▀ ▀▀ ▀▀▀ ▀▀ ▀ ▀▀ ▀▀ \n" \
+_B " ▀█▄▄▄▄▄▄▄▄▀ \n" \
+_B " ▀▀▀▀▀▀ \n" \
+RST "\n"
diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c
index 688c4ade..ce9fc8fc 100644
--- a/src/irmd/configfile.c
+++ b/src/irmd/configfile.c
@@ -47,8 +47,12 @@
#include <string.h>
#include <toml.h>
#include <arpa/inet.h>
+#ifdef __FreeBSD__
+#include <sys/socket.h>
+#endif
#define ERRBUFSZ 200
+#define DATUMSZ 256
static int toml_hash(toml_table_t * table,
struct layer_info * info)
@@ -157,14 +161,66 @@ static int toml_eth_dix(toml_table_t * table,
return 0;
}
-static int toml_udp(toml_table_t * table,
- struct ipcp_config * conf)
+static int toml_udp4(toml_table_t * table,
+ struct ipcp_config * conf)
+{
+ struct udp4_config * udp4;
+ toml_datum_t ip;
+ toml_datum_t port;
+ toml_datum_t dns;
+
+ *conf = udp4_default_conf;
+ udp4 = &conf->udp4;
+
+ ip = toml_string_in(table, "ip");
+ if (!ip.ok) {
+ log_err("No IP address specified!");
+ goto fail_ip;
+ }
+
+ if (inet_pton (AF_INET, ip.u.s, &udp4->ip_addr.s_addr) != 1) {
+ log_err("Failed to parse IPv4 address %s.", ip.u.s);
+ goto fail_addr;
+ }
+
+ port = toml_int_in(table, "port");
+ if (port.ok)
+ udp4->port = port.u.i;
+
+ dns = toml_string_in(table, "dns");
+ if (dns.ok) {
+ if (inet_pton(AF_INET, dns.u.s, &udp4->dns_addr.s_addr) < 0) {
+ log_err("Failed to parse DNS address %s.", ip.u.s);
+ goto fail_dns;
+ }
+
+ free(dns.u.s);
+ }
+
+ free(ip.u.s);
+
+ return 0;
+
+ fail_dns:
+ free(dns.u.s);
+ fail_addr:
+ free(ip.u.s);
+ fail_ip:
+ return -1;
+}
+
+static int toml_udp6(toml_table_t * table,
+ struct ipcp_config * conf)
{
+ struct in6_addr ip6;
+ struct in6_addr dns6;
toml_datum_t ip;
toml_datum_t port;
toml_datum_t dns;
- *conf = udp_default_conf;
+ *conf = udp6_default_conf;
+ ip6 = conf->udp6.ip_addr;
+ dns6 = conf->udp6.dns_addr;
ip = toml_string_in(table, "ip");
if (!ip.ok) {
@@ -172,18 +228,18 @@ static int toml_udp(toml_table_t * table,
goto fail_ip;
}
- if (inet_pton (AF_INET, ip.u.s, &conf->udp.ip_addr) != 1) {
+ if (inet_pton (AF_INET6, ip.u.s, &ip6.s6_addr) != 1) {
log_err("Failed to parse IPv4 address %s.", ip.u.s);
goto fail_addr;
}
port = toml_int_in(table, "port");
if (port.ok)
- conf->udp.port = port.u.i;
+ conf->udp6.port = port.u.i;
dns = toml_string_in(table, "dns");
if (dns.ok) {
- if (inet_pton(AF_INET, dns.u.s, &conf->udp.dns_addr) < 0) {
+ if (inet_pton(AF_INET6, dns.u.s, &dns6.s6_addr) < 0) {
log_err("Failed to parse DNS address %s.", ip.u.s);
goto fail_dns;
}
@@ -214,26 +270,160 @@ static int toml_broadcast(toml_table_t * table,
return 0;
}
+#define BETWEEN(a, b, c) ((a) >= (b) && (a) <= (c))
+#define DHT(conf, x) (conf)->dht.params.x
+static int toml_dir(toml_table_t * table,
+ struct dir_config * conf)
+{
+ toml_datum_t dir;
+ toml_datum_t alpha;
+ toml_datum_t t_expire;
+ toml_datum_t t_refresh;
+ toml_datum_t t_replicate;
+ toml_datum_t k;
+
+ dir = toml_string_in(table, "directory");
+ if (dir.ok) {
+ log_dbg("Found directory type: %s", dir.u.s);
+ if (strlen(dir.u.s) > DATUMSZ) {
+ log_err("Directory name too long: %s", dir.u.s);
+ free(dir.u.s);
+ return -1;
+ }
+ if (strcmp(dir.u.s, "DHT") == 0)
+ conf->pol = DIR_DHT;
+ else if (strcmp(dir.u.s, "dht") == 0)
+ conf->pol = DIR_DHT;
+ else {
+ log_err("Unknown directory type: %s", dir.u.s);
+ free(dir.u.s);
+ return -EINVAL;
+ }
+ free(dir.u.s);
+ }
+
+ switch(conf->pol) {
+ case DIR_DHT:
+ log_info("Using DHT directory policy.");
+ alpha = toml_int_in(table, "dht_alpha");
+ if (alpha.ok) {
+ if (!BETWEEN(alpha.u.i,
+ DHT_ALPHA_MIN, DHT_ALPHA_MAX)) {
+ log_err("Invalid alpha value: %ld",
+ (long) alpha.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, alpha) = alpha.u.i;
+ }
+ t_expire = toml_int_in(table, "dht_t_expire");
+ if (t_expire.ok) {
+ if (!BETWEEN(t_expire.u.i,
+ DHT_T_EXPIRE_MIN, DHT_T_EXPIRE_MAX)) {
+ log_err("Invalid expire time: %ld",
+ (long) t_expire.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, t_expire) = t_expire.u.i;
+ }
+ t_refresh = toml_int_in(table, "dht_t_refresh");
+ if (t_refresh.ok) {
+ if (!BETWEEN(t_refresh.u.i,
+ DHT_T_REFRESH_MIN, DHT_T_REFRESH_MAX)) {
+ log_err("Invalid refresh time: %ld",
+ (long) t_refresh.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, t_refresh) = t_refresh.u.i;
+ }
+ t_replicate = toml_int_in(table, "dht_t_replicate");
+ if (t_replicate.ok) {
+ if (!BETWEEN(t_replicate.u.i,
+ DHT_T_REPLICATE_MIN, DHT_T_REPLICATE_MAX)) {
+ log_err("Invalid replication time: %ld",
+ (long) t_replicate.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, t_replicate) = t_replicate.u.i;
+ }
+ k = toml_int_in(table, "dht_k");
+ if (k.ok) {
+ if (!BETWEEN(k.u.i, DHT_K_MIN, DHT_K_MAX)) {
+ log_err("Invalid replication factor: %ld",
+ (long) k.u.i);
+ return -EINVAL;
+ }
+ DHT(conf, k) = k.u.i;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ return 0;
+}
+
static int toml_routing(toml_table_t * table,
struct dt_config * conf)
{
toml_datum_t routing;
+ toml_datum_t t_recalc;
+ toml_datum_t t_update;
+ toml_datum_t t_timeo;
routing = toml_string_in(table, "routing");
if (routing.ok) {
- if (strcmp(routing.u.s, "link-state") == 0)
- conf->routing_type = ROUTING_LINK_STATE;
- else if (strcmp(routing.u.s, "lfa") == 0)
- conf->routing_type = ROUTING_LINK_STATE_LFA;
- else if (strcmp(routing.u.s, "ecmp") == 0)
- conf->routing_type = ROUTING_LINK_STATE_ECMP;
- else
- conf->routing_type = ROUTING_INVALID;
+ if (strcmp(routing.u.s, "link-state") == 0) {
+ conf->routing.pol = ROUTING_LINK_STATE;
+ conf->routing.ls.pol = LS_SIMPLE;
+ } else if (strcmp(routing.u.s, "lfa") == 0) {
+ conf->routing.pol = ROUTING_LINK_STATE;
+ conf->routing.ls.pol = LS_LFA;
+ } else if (strcmp(routing.u.s, "ecmp") == 0) {
+ conf->routing.pol = ROUTING_LINK_STATE;
+ conf->routing.ls.pol = LS_ECMP;
+ } else {
+ conf->routing.pol = ROUTING_INVALID;
+ return -EINVAL;
+ }
free(routing.u.s);
}
- if (conf->routing_type == ROUTING_INVALID)
- return -1;
+ switch (conf->routing.pol) {
+ case ROUTING_LINK_STATE:
+ log_info("Using Link State routing policy.");
+ t_recalc = toml_int_in(table, "ls_t_recalc");
+ if (t_recalc.ok) {
+ if (t_recalc.u.i < 1) {
+ log_err("Invalid ls_t_recalc value: %ld",
+ (long) t_recalc.u.i);
+ return -EINVAL;
+ }
+ conf->routing.ls.t_recalc = t_recalc.u.i;
+ }
+ t_update = toml_int_in(table, "ls_t_update");
+ if (t_update.ok) {
+ if (t_update.u.i < 1) {
+ log_err("Invalid ls_t_update value: %ld",
+ (long) t_update.u.i);
+ return -EINVAL;
+ }
+ conf->routing.ls.t_update = t_update.u.i;
+ }
+ t_timeo = toml_int_in(table, "ls_t_timeo");
+ if (t_timeo.ok) {
+ if (t_timeo.u.i < 1) {
+ log_err("Invalid ls_t_timeo value: %ld",
+ (long) t_timeo.u.i);
+ return -EINVAL;
+ }
+ conf->routing.ls.t_timeo = t_timeo.u.i;
+ }
+ break;
+ default:
+ log_err("Invalid routing policy: %d", conf->routing.pol);
+ return -EINVAL;
+ }
return 0;
}
@@ -311,12 +501,12 @@ static int toml_dt(toml_table_t * table,
static int toml_unicast(toml_table_t * table,
struct ipcp_config * conf)
{
-
-
*conf = uni_default_conf;
- if (toml_hash(table, &conf->layer_info) < 0)
+ if (toml_dir(table, &conf->unicast.dir) < 0) {
+ log_err("Invalid directory configuration.");
return -1;
+ }
if (toml_dt(table, &conf->unicast.dt) < 0) {
log_err("Invalid DT configuration.");
@@ -333,6 +523,7 @@ static int toml_unicast(toml_table_t * table,
return -1;
}
+
return 0;
}
@@ -504,8 +695,11 @@ static int toml_ipcp(toml_table_t * table,
case IPCP_ETH_LLC:
ret = toml_eth_llc(table, conf);
break;
- case IPCP_UDP:
- ret = toml_udp(table, conf);
+ case IPCP_UDP4:
+ ret = toml_udp4(table, conf);
+ break;
+ case IPCP_UDP6:
+ ret = toml_udp6(table, conf);
break;
case IPCP_BROADCAST:
ret = toml_broadcast(table, conf);
@@ -563,7 +757,7 @@ static int toml_ipcp_list(toml_table_t * table,
}
info.type = type;
- strcpy(info.name,key);
+ strcpy(info.name, key);
conf.type = type;
ret = toml_ipcp(toml_table_in(table, key), &info, &conf);
@@ -691,18 +885,63 @@ static int toml_prog_list(toml_array_t * progs,
return ret;
}
+static int cp_chk_path(char * buf,
+ char * path)
+{
+ char * rp;
+
+ assert(path != NULL);
+
+ rp = realpath(path, NULL);
+ if (rp == NULL) {
+ log_err("Failed to check path %s: %s.", path, strerror(errno));
+ goto fail_rp;
+ }
+
+ if (strlen(rp) > NAME_PATH_SIZE) {
+ log_err("File path too long: %s.", rp);
+ goto fail_len;
+ }
+
+ strcpy(buf, rp);
+ free(rp);
+ free(path);
+
+ return 0;
+
+ fail_len:
+ free(rp);
+ fail_rp:
+ free(path);
+ return -1;
+}
+
static int toml_name(toml_table_t * table,
const char * name)
{
- toml_array_t * progs;
- toml_array_t * args;
- toml_datum_t lb;
+ toml_array_t * progs;
+ toml_array_t * args;
+ toml_datum_t lb;
+ toml_datum_t senc;
+ toml_datum_t scrt;
+ toml_datum_t skey;
+ toml_datum_t cenc;
+ toml_datum_t ccrt;
+ toml_datum_t ckey;
+
struct name_info info = {
.pol_lb = LB_SPILL
};
log_dbg("Found service name %s in configuration file.", name);
+ if (strlen(name) > NAME_SIZE) {
+ log_err("Name too long: %s", name);
+ return -1;
+ }
+
+ strcpy(info.name, name);
+
lb = toml_string_in(table, "lb");
if (lb.ok) {
if (strcmp(lb.u.s, "spill") == 0)
@@ -718,8 +957,29 @@ static int toml_name(toml_table_t * table,
log_err("Invalid load-balancing policy for %s.", name);
return -1;
}
+ senc = toml_string_in(table, "server_enc_file");
+ if (senc.ok && cp_chk_path(info.s.enc, senc.u.s) < 0)
+ return -1;
- strcpy(info.name, name);
+ scrt = toml_string_in(table, "server_crt_file");
+ if (scrt.ok && cp_chk_path(info.s.crt, scrt.u.s) < 0)
+ return -1;
+
+ skey = toml_string_in(table, "server_key_file");
+ if (skey.ok && cp_chk_path(info.s.key, skey.u.s) < 0)
+ return -1;
+
+ cenc = toml_string_in(table, "client_enc_file");
+ if (cenc.ok && cp_chk_path(info.c.enc, cenc.u.s) < 0)
+ return -1;
+
+ ccrt = toml_string_in(table, "client_crt_file");
+ if (ccrt.ok && cp_chk_path(info.c.crt, ccrt.u.s) < 0)
+ return -1;
+
+ ckey = toml_string_in(table, "client_key_file");
+ if (ckey.ok && cp_chk_path(info.c.key, ckey.u.s) < 0)
+ return -1;
if (name_create(&info) < 0) {
log_err("Failed to create name %s.", name);
@@ -762,23 +1022,24 @@ static int toml_toplevel(toml_table_t * table,
toml_table_t * subtable;
subtable = toml_table_in(table, key);
-
- if (strcmp(key, "local") == 0)
+ if (strcmp(key, "name") == 0)
+ return toml_name_list(subtable);
+ else if (strcmp(key, "local") == 0)
return toml_ipcp_list(subtable, IPCP_LOCAL);
else if (strcmp(key, "eth-dix") == 0)
return toml_ipcp_list(subtable, IPCP_ETH_DIX);
else if (strcmp(key, "eth-llc") == 0)
return toml_ipcp_list(subtable, IPCP_ETH_LLC);
- else if (strcmp(key, "udp") == 0)
- return toml_ipcp_list(subtable, IPCP_UDP);
+ else if (strcmp(key, "udp4") == 0)
+ return toml_ipcp_list(subtable, IPCP_UDP4);
+ else if (strcmp(key, "udp6") == 0)
+ return toml_ipcp_list(subtable, IPCP_UDP6);
else if (strcmp(key, "broadcast") == 0)
return toml_ipcp_list(subtable, IPCP_BROADCAST);
else if (strcmp(key, "unicast") == 0)
return toml_ipcp_list(subtable, IPCP_UNICAST);
- else if (strcmp(key, "name") == 0)
- return toml_name_list(subtable);
-
- log_err("Unkown toplevel key: %s.", key);
+ else
+ log_err("Unkown toplevel key: %s.", key);
return -1;
}
@@ -838,7 +1099,8 @@ int irm_configure(const char * path)
rp = realpath(path, NULL);
if (rp == NULL) {
- log_err("Failed to resolve path for %s", path);
+ log_err("Failed to check path for %s: %s.",
+ path, strerror(errno));
goto fail_resolve;
}
diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c
index 5a9a79d3..6226aeda 100644
--- a/src/irmd/ipcp.c
+++ b/src/irmd/ipcp.c
@@ -83,28 +83,30 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
{
int sockfd;
uint8_t buf[SOCK_BUF_SIZE];
- char * sock_path;
+ char * spath;
ssize_t len;
- ipcp_msg_t * recv_msg;
struct timeval tv;
struct timespec tic;
struct timespec toc;
- bool dealloc = false;
+ bool may_fail = false;
if (kill(pid, 0) < 0)
return NULL;
- sock_path = ipcp_sock_path(pid);
- if (sock_path == NULL)
+ spath = sock_path(pid, IPCP_SOCK_PATH_PREFIX);
+ if (spath == NULL) {
+ log_err("Failed to get IPCP socket path for pid %d.", pid);
return NULL;
+ }
- sockfd = client_socket_open(sock_path);
+ sockfd = client_socket_open(spath);
if (sockfd < 0) {
- free(sock_path);
+ log_err("Failed to open client socket at %s.", spath);
+ free(spath);
return NULL;
}
- free(sock_path);
+ free(spath);
len = ipcp_msg__get_packed_size(msg);
if (len == 0 || len >= SOCK_BUF_SIZE) {
@@ -127,6 +129,7 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
tv.tv_usec = (REG_TIMEOUT % 1000) * 1000;
break;
case IPCP_MSG_CODE__IPCP_QUERY:
+ may_fail = true; /* name not always in Layer */
tv.tv_sec = QUERY_TIMEOUT / 1000;
tv.tv_usec = (QUERY_TIMEOUT % 1000) * 1000;
break;
@@ -139,7 +142,7 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
tv.tv_usec = (FLOW_ALLOC_TIMEOUT % 1000) * 1000;
break;
case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC:
- dealloc = true;
+ may_fail = true;
tv.tv_sec = 0; /* FIX DEALLOC: don't wait for dealloc */
tv.tv_usec = 500;
break;
@@ -167,17 +170,15 @@ ipcp_msg_t * send_recv_ipcp_msg(pid_t pid,
pthread_cleanup_pop(true); /* close socket */
if (len > 0)
- recv_msg = ipcp_msg__unpack(NULL, len, buf);
- else {
- if (errno == EAGAIN && !dealloc) {
- int diff = ts_diff_ms(&tic, &toc);
- log_warn("IPCP %s timed out after %d ms.",
- str_ipcp_cmd(msg->code), diff);
- }
- return NULL;
+ return ipcp_msg__unpack(NULL, len, buf);
+
+ if (errno == EAGAIN && !may_fail) {
+ int diff = ts_diff_ms(&toc, &tic);
+ log_warn("IPCP %s timed out after %d ms.",
+ str_ipcp_cmd(msg->code), diff);
}
- return recv_msg;
+ return NULL;
}
int ipcp_bootstrap(pid_t pid,
@@ -496,7 +497,7 @@ int ipcp_flow_alloc_resp(const struct flow_info * flow,
msg.pid = flow->n_pid;
msg.has_response = true;
msg.response = response;
- msg.has_pk = true;
+ msg.has_pk = response == 0;
msg.pk.data = data.data;
msg.pk.len = data.len;
diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h
index cf8f6953..3e54904a 100644
--- a/src/irmd/irmd.h
+++ b/src/irmd/irmd.h
@@ -39,7 +39,7 @@ int connect_ipcp(pid_t pid,
const char * component,
qosspec_t qs);
-int name_create(const struct name_info * info);
+int name_create(struct name_info * info);
int name_reg(const char * name,
pid_t pid);
diff --git a/src/irmd/main.c b/src/irmd/main.c
index bc13fa7c..834a7a8c 100644
--- a/src/irmd/main.c
+++ b/src/irmd/main.c
@@ -40,6 +40,7 @@
#include <ouroboros/lockfile.h>
#include <ouroboros/logs.h>
#include <ouroboros/pthread.h>
+#include <ouroboros/random.h>
#include <ouroboros/rib.h>
#include <ouroboros/shm_rdrbuff.h>
#include <ouroboros/sockets.h>
@@ -50,9 +51,11 @@
#include "irmd.h"
#include "ipcp.h"
+#include "oap.h"
#include "reg/reg.h"
#include "configfile.h"
+#include <dirent.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
@@ -71,15 +74,24 @@
#define SHM_SAN_HOLDOFF 1000 /* ms */
#define IPCP_HASH_LEN(p) hash_len((p)->dir_hash_algo)
#define BIND_TIMEOUT 10 /* ms */
+#define TIMESYNC_SLACK 100 /* ms */
+#define OAP_SEEN_TIMER 20 /* s */
#define DEALLOC_TIME 300 /* s */
-#define MSGBUFSZ 2048
enum irm_state {
IRMD_NULL = 0,
+ IRMD_INIT,
IRMD_RUNNING,
IRMD_SHUTDOWN
};
+struct oaph {
+ struct list_head next;
+
+ uint64_t stamp;
+ uint8_t id[OAP_ID_SIZE];
+};
+
struct cmd {
struct list_head next;
@@ -93,6 +105,12 @@ struct {
#ifdef HAVE_TOML
char * cfg_file; /* configuration file path */
#endif
+ struct {
+ struct auth_ctx * ctx; /* default authentication ctx */
+ struct list_head list; /* OAP headers seen before */
+ pthread_mutex_t mtx; /* mutex for OAP headers */
+ } auth;
+
struct lockfile * lf; /* single irmd per system */
struct shm_rdrbuff * rdrb; /* rdrbuff for packets */
@@ -173,8 +191,11 @@ static pid_t spawn_ipcp(struct ipcp_info * info)
case IPCP_BROADCAST:
exec_name = IPCP_BROADCAST_EXEC;
break;
- case IPCP_UDP:
- exec_name = IPCP_UDP_EXEC;
+ case IPCP_UDP4:
+ exec_name = IPCP_UDP4_EXEC;
+ break;
+ case IPCP_UDP6:
+ exec_name = IPCP_UDP6_EXEC;
break;
case IPCP_ETH_LLC:
exec_name = IPCP_ETH_LLC_EXEC;
@@ -217,7 +238,7 @@ static pid_t spawn_ipcp(struct ipcp_info * info)
}
info->pid = pid;
- info->state = IPCP_BOOT;
+ info->state = IPCP_INIT;
return 0;
}
@@ -312,7 +333,7 @@ int bootstrap_ipcp(pid_t pid,
goto fail;
}
- if (conf->type == IPCP_UDP)
+ if (conf->type == IPCP_UDP4 || conf->type == IPCP_UDP6)
conf->layer_info.dir_hash_algo = (enum pol_dir_hash) HASH_MD5;
if (ipcp_bootstrap(pid, conf, &layer)) {
@@ -320,7 +341,7 @@ int bootstrap_ipcp(pid_t pid,
goto fail;
}
- info.state = IPCP_BOOTSTRAPPED;
+ info.state = IPCP_BOOT;
if (reg_set_layer_for_ipcp(&info, &layer) < 0) {
log_err("Failed to set layer info for IPCP.");
@@ -352,6 +373,8 @@ int enroll_ipcp(pid_t pid,
goto fail;
}
+ info.state = IPCP_BOOT;
+
if (reg_set_layer_for_ipcp(&info, &layer) < 0) {
log_err("Failed to set layer info for IPCP.");
goto fail;
@@ -425,6 +448,71 @@ static int disconnect_ipcp(pid_t pid,
return 0;
}
+static void name_update_sec_paths(struct name_info * info)
+{
+ char * srv_dir = OUROBOROS_SRV_CRT_DIR;
+ char * cli_dir = OUROBOROS_CLI_CRT_DIR;
+
+ assert(info != NULL);
+
+ if (strlen(info->s.enc) == 0)
+ sprintf(info->s.enc, "%s/%s/enc.cfg", srv_dir, info->name);
+
+ if (strlen(info->s.crt) == 0)
+ sprintf(info->s.crt, "%s/%s/crt.pem", srv_dir, info->name);
+
+ if (strlen(info->s.key) == 0)
+ sprintf(info->s.key, "%s/%s/key.pem", srv_dir, info->name);
+
+ if (strlen(info->c.enc) == 0)
+ sprintf(info->c.enc, "%s/%s/enc.cfg", cli_dir, info->name);
+
+ if (strlen(info->c.crt) == 0)
+ sprintf(info->c.crt, "%s/%s/crt.pem", cli_dir, info->name);
+
+ if (strlen(info->c.key) == 0)
+ sprintf(info->c.key, "%s/%s/key.pem", cli_dir, info->name);
+}
+
+int name_create(struct name_info * info)
+{
+ int ret;
+
+ assert(info != NULL);
+
+ name_update_sec_paths(info);
+
+ ret = reg_create_name(info);
+ if (ret == -EEXIST) {
+ log_info("Name %s already exists.", info->name);
+ return 0;
+ }
+
+ if (ret < 0) {
+ log_err("Failed to create name %s.", info->name);
+ return -1;
+ }
+
+ log_info("Created new name: %s.", info->name);
+
+ return 0;
+}
+
+static int name_destroy(const char * name)
+{
+
+ assert(name != NULL);
+
+ if (reg_destroy_name(name) < 0) {
+ log_err("Failed to destroy name %s.", name);
+ return -1;
+ }
+
+ log_info("Destroyed name: %s.", name);
+
+ return 0;
+}
+
int bind_program(char ** exec,
const char * name,
uint8_t flags)
@@ -448,10 +536,8 @@ int bind_program(char ** exec,
if (!reg_has_name(name)) {
ni.pol_lb = LB_SPILL;
strcpy(ni.name, name);
- if (reg_create_name(&ni) < 0) {
- log_err("Failed to create name %s.", name);
+ if (name_create(&ni) < 0)
goto fail_name;
- }
}
if (reg_bind_prog(name, exec, flags) < 0) {
@@ -497,10 +583,8 @@ int bind_process(pid_t pid,
if (!reg_has_name(name)) {
ni.pol_lb = LB_SPILL;
strcpy(ni.name, name);
- if (reg_create_name(&ni) < 0) {
- log_err("Failed to create name %s.", name);
+ if (name_create(&ni) < 0)
goto fail;
- }
}
if (reg_bind_proc(name, pid) < 0) {
@@ -581,43 +665,6 @@ static int list_ipcps(ipcp_list_msg_t *** ipcps,
return -1;
}
-int name_create(const struct name_info * info)
-{
- int ret;
-
- assert(info != NULL);
-
- ret = reg_create_name(info);
- if (ret == -EEXIST) {
- log_info("Name %s already exists.", info->name);
- return 0;
- }
-
- if (ret < 0) {
- log_err("Failed to create name %s.", info->name);
- return -1;
- }
-
- log_info("Created new name: %s.", info->name);
-
- return 0;
-}
-
-static int name_destroy(const char * name)
-{
-
- assert(name != NULL);
-
- if (reg_destroy_name(name) < 0) {
- log_err("Failed to destroy name %s.", name);
- return -1;
- }
-
- log_info("Destroyed name: %s.", name);
-
- return 0;
-}
-
static int list_names(name_info_msg_t *** names,
size_t * n_names)
{
@@ -760,67 +807,279 @@ static void __cleanup_flow(void * flow)
reg_destroy_flow(((struct flow_info *) flow)->id);
}
+static bool file_exists(const char * path)
+{
+ struct stat s;
+
+ if (stat(path, &s) < 0 && errno == ENOENT) {
+ log_dbg("File %s does not exist.", path);
+ return false;
+ }
+
+ return true;
+}
+
+static int load_credentials(const char * name,
+ const struct name_sec_paths * paths,
+ void ** pkp,
+ void ** crt,
+ bool * crypt)
+{
+ assert(paths != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ *pkp = NULL;
+ *crt = NULL;
+
+ /* TODO: Allow configuration. For now, encrypt if path exists */
+ *crypt = file_exists(paths->enc);
+ if (*crypt)
+ log_info("Encryption enabled for %s.", name);
+
+ if (!file_exists(paths->crt) || !file_exists(paths->key)) {
+ log_info("No security info for %s.", name);
+ return 0;
+ }
+
+ if (crypt_load_crt_file(paths->crt, crt) < 0) {
+ log_err("Failed to load %s for %s.", paths->crt, name);
+ goto fail_crt;
+ }
+
+ if (crypt_load_privkey_file(paths->key, pkp) < 0) {
+ log_err("Failed to load %s for %s.", paths->key, name);
+ goto fail_key;
+ }
+
+ log_info("Loaded security keys for %s.", name);
+
+ return 0;
+
+ fail_key:
+ crypt_free_crt(*crt);
+ *crt = NULL;
+ fail_crt:
+ return -EAUTH;
+}
+
+static int load_srv_credentials(const char * name,
+ void ** pkp,
+ void ** crt,
+ bool * crypt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.s, pkp, crt, crypt);
+}
+
+static int load_cli_credentials(const char * name,
+ void ** pkp,
+ void ** crt,
+ bool * crypt)
+{
+ struct name_info info;
+
+ assert(name != NULL);
+ assert(pkp != NULL);
+ assert(crt != NULL);
+
+ if (reg_get_name_info(name, &info) < 0) {
+ log_err("Failed to get name info for %s.", name);
+ return -ENAME;
+ }
+
+ return load_credentials(name, &info.c, pkp, crt, crypt);
+}
+
+#define ID_IS_EQUAL(id1, id2) (memcmp(id1, id2, OAP_ID_SIZE) == 0)
+static int irm_check_oap_hdr(const struct oap_hdr * oap_hdr,
+ time_t mpl)
+{
+ struct list_head * p;
+ struct list_head * h;
+ struct timespec now;
+ struct oaph * new;
+ uint64_t stamp;
+ uint64_t cur;
+ uint8_t * id;
+ ssize_t delta;
+
+ assert(oap_hdr != NULL);
+
+ stamp = oap_hdr->timestamp;
+ id = oap_hdr->id.data;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ cur = TS_TO_UINT64(now);
+
+ delta = (ssize_t)(cur - stamp) / MILLION;
+ if (delta > mpl)
+ log_warn("Transit time exceeds MPL by %zd ms.", delta);
+ if (delta < -TIMESYNC_SLACK)
+ log_warn("OAP header sent %zd ms from the future.", -delta);
+
+ new = malloc(sizeof(*new));
+ if (new == NULL) {
+ log_err("Failed to allocate memory for OAP element.");
+ return -ENOMEM;
+ }
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ if (cur > oaph->stamp + OAP_SEEN_TIMER * BILLION) {
+ list_del(&oaph->next);
+ free(oaph);
+ continue;
+ }
+
+ if (oaph->stamp == stamp && ID_IS_EQUAL(oaph->id, id)) {
+ log_warn("OAP header already known: " HASH_FMT64 ".",
+ HASH_VAL64(id));
+ goto fail_replay;
+ }
+ }
+
+ memcpy(new->id, id, OAP_ID_SIZE);
+ new->stamp = stamp;
+
+ list_add_tail(&new->next, &irmd.auth.list);
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+
+ return 0;
+
+ fail_replay:
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ free(new);
+ return -EAUTH;
+}
+
+static int irm_auth_peer(const char * name,
+ const struct oap_hdr * oap_hdr,
+ const struct oap_hdr * r_oap_hdr)
+{
+ void * crt;
+ void * pk;
+ buffer_t sign;
+ const char * n = name == NULL ? "<client>" : name;
+
+ if (memcmp(r_oap_hdr->id.data, oap_hdr->id.data, OAP_ID_SIZE) != 0) {
+ log_err("OAP ID mismatch in flow allocation.");
+ goto fail_check;
+ }
+
+ if (r_oap_hdr->crt.len == 0) {
+ log_info("No certificate provided by %s.", n);
+ return 0;
+ }
+
+ if (crypt_load_crt_der(r_oap_hdr->crt, &crt) < 0) {
+ log_err("Failed to load certificate from %s.", n);
+ goto fail_check;
+ }
+
+ log_dbg("Loaded peer certificate for %s.", n);
+
+ if (name != NULL) {
+ if (crypt_check_crt_name(crt, n) < 0) {
+ log_err("Certificate does not match %s.", n);
+ goto fail_crt;
+ }
+ log_dbg("Certificate matches name %s.", n);
+ }
+
+ if (crypt_get_pubkey_crt(crt, &pk) < 0) {
+ log_err("Failed to get pubkey from certificate for %s.", n);
+ goto fail_crt;
+ }
+
+ log_dbg("Got public key from certificate for %s.", n);
+
+ if (auth_verify_crt(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to verify peer %s with CA store.", n);
+ goto fail_crt;
+ }
+
+ log_info("Successfully verified peer certificate for %s.", n);
+
+ sign = r_oap_hdr->hdr;
+ sign.len -= (r_oap_hdr->sig.len + sizeof(uint16_t));
+
+ if (auth_verify_sig(pk, sign, r_oap_hdr->sig) < 0) {
+ log_err("Failed to verify signature for peer %s.", n);
+ goto fail_check_sig;
+ }
+
+ crypt_free_key(pk);
+ crypt_free_crt(crt);
+
+ log_info("Successfully authenticated %s.", n);
+
+ return 0;
+
+ fail_check_sig:
+ crypt_free_key(pk);
+ fail_crt:
+ crypt_free_crt(crt);
+ fail_check:
+ return -1;
+}
+
static int flow_accept(struct flow_info * flow,
+ buffer_t * symmkey,
buffer_t * data,
struct timespec * abstime)
{
- uint8_t buf[MSGBUFSZ];
- buffer_t lpk; /* local public key */
- buffer_t rpk; /* remote public key */
- void * pkp; /* my public/private key pair */
- ssize_t key_len;
- uint8_t * s;
- int err;
+ struct oap_hdr oap_hdr; /* incoming request */
+ struct oap_hdr r_oap_hdr; /* outgoing response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ char name[NAME_SIZE + 1]; /* name for flow */
+ void * pkp = NULL; /* signing private key */
+ void * crt = NULL; /* signing certificate */
+ int err;
+ bool crypt;
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
if (!reg_has_proc(flow->n_pid)) {
log_err("Unknown process %d calling accept.", flow->n_pid);
err = -EINVAL;
- goto fail;
- }
-
- s = malloc(SYMMKEYSZ);
- if (s == NULL) {
- log_err("Failed to malloc symmkey.");
- err = -ENOMEM;
- goto fail;
- }
-
- key_len = crypt_dh_pkp_create(&pkp, buf);
- if (key_len < 0) {
- log_err("Failed to generate key pair.");
- err = -ECRYPT;
- goto fail_pkp;
+ goto fail_flow;
}
- lpk.data = buf;
- lpk.len = (size_t) key_len;
-
- log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
-
if (reg_create_flow(flow) < 0) {
log_err("Failed to create flow.");
err = -EBADF;
goto fail_flow;
}
- if (reg_prepare_flow_accept(flow, &lpk) < 0) {
+ if (reg_prepare_flow_accept(flow) < 0) {
log_err("Failed to prepare accept.");
err = -EBADF;
goto fail_wait;
}
pthread_cleanup_push(__cleanup_flow, flow);
- pthread_cleanup_push(__cleanup_pkp, pkp);
- pthread_cleanup_push(free, s);
- err = reg_wait_flow_accepted(flow, &rpk, abstime);
+ err = reg_wait_flow_accepted(flow, &oap_hdr.hdr, abstime);
pthread_cleanup_pop(false);
- pthread_cleanup_pop(false);
- pthread_cleanup_pop(false);
if (err == -ETIMEDOUT) {
log_err("Flow accept timed out.");
@@ -835,45 +1094,135 @@ static int flow_accept(struct flow_info * flow,
assert(err == 0);
- if (flow->qs.cypher_s != 0) { /* crypto requested */
- if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ if (reg_get_name_for_flow_id(name, flow->id) < 0) {
+ log_err("Failed to get name for flow %d.", flow->id);
+ err = -EIPCP;
+ goto fail_cred;
+ }
+
+ log_dbg("IPCP %d accepting flow %d for %s.",
+ flow->n_pid, flow->id, name);
+
+ if (load_srv_credentials(name, &pkp, &crt, &crypt) < 0) {
+ log_err("Failed to load security keys for %s.", name);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (oap_hdr_decode(oap_hdr.hdr, &oap_hdr) < 0) {
+ log_err("Failed to decode OAP header from %s.", name);
+ err = -EIPCP;
+ goto fail_oap_hdr;
+ }
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_rcv(&oap_hdr);
+#endif
+ if (irm_check_oap_hdr(&oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ goto fail_oap_hdr;
+ }
+
+ if (crypt && oap_hdr.eph.len == 0) {
+ log_warn("Encryption required but no key provided.");
+ err = -ECRYPT;
+ goto fail_oap_hdr;
+ }
+
+ if (oap_hdr.eph.len > 0) { /* crypto requested */
+ uint8_t * s; /* symmetric encryption key */
+ ssize_t key_len; /* length of local pubkey */
+ void * pkp = NULL; /* ephemeral private key pair */
+
+ s = malloc(SYMMKEYSZ);
+ if (s == NULL) {
+ log_err("Failed to malloc symmkey.");
+ err = -ENOMEM;
+ goto fail_keys;
+ }
+
+ key_len = crypt_dh_pkp_create(&pkp, buf);
+ if (key_len < 0) {
+ free(s);
+ log_err("Failed to generate key pair.");
+ err = -ECRYPT;
+ goto fail_keys;
+ }
+
+ lpk.data = buf;
+ lpk.len = (size_t) key_len;
+
+ log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
+
+ if (crypt_dh_derive(pkp, oap_hdr.eph, s) < 0) {
log_err("Failed to derive secret for %d.", flow->id);
+ crypt_dh_pkp_destroy(pkp);
+ free(s);
err = -ECRYPT;
goto fail_derive;
}
- freebuf(rpk);
- data->data = s;
- data->len = SYMMKEYSZ;
- s= NULL;
- } else {
- clrbuf(lpk);
+
+ symmkey->data = s;
+ symmkey->len = SYMMKEYSZ;
+
+ crypt_dh_pkp_destroy(pkp);
}
- if (ipcp_flow_alloc_resp(flow, 0, lpk) < 0) {
+ if (oap_hdr_init(oap_hdr.id, pkp, crt, lpk, *data, &r_oap_hdr) < 0) {
+ log_err("Failed to create OAP header.");
+ err = -ENOMEM;
+ goto fail_r_oap_hdr;
+ }
+
+ if (irm_auth_peer(NULL, &r_oap_hdr, &oap_hdr) < 0) {
+ log_err("Failed to auth %s client, flow %d.", name, flow->id);
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
+
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_snd(&r_oap_hdr);
+#endif
+ if (ipcp_flow_alloc_resp(flow, 0, r_oap_hdr.hdr) < 0) {
log_err("Failed to respond to flow allocation.");
- err = -EIPCP;
- goto fail_alloc_resp;
+ goto fail_resp;
}
- crypt_dh_pkp_destroy(pkp);
- free(s);
+ log_info("Flow %d accepted by %d for %s.",
+ flow->id, flow->n_pid, name);
+
+ oap_hdr_fini(&oap_hdr);
+ oap_hdr_fini(&r_oap_hdr);
return 0;
+ fail_r_oap_hdr:
+ freebuf(*symmkey);
fail_derive:
- freebuf(rpk);
clrbuf(lpk);
+ fail_keys:
+ oap_hdr_fini(&oap_hdr);
+ fail_oap_hdr:
+ crypt_free_crt(crt);
+ crypt_free_key(pkp);
+ fail_cred:
+ assert(lpk.data == NULL && lpk.len == 0);
ipcp_flow_alloc_resp(flow, err, lpk);
- fail_alloc_resp:
- flow->state = FLOW_NULL;
fail_wait:
reg_destroy_flow(flow->id);
fail_flow:
- crypt_dh_pkp_destroy(pkp);
- fail_pkp:
- free(s);
- fail:
return err;
+
+ fail_resp:
+ flow->state = FLOW_NULL;
+ oap_hdr_fini(&r_oap_hdr);
+ freebuf(*symmkey);
+ clrbuf(lpk);
+ oap_hdr_fini(&oap_hdr);
+ reg_destroy_flow(flow->id);
+ return -EIPCP;
}
static int flow_join(struct flow_info * flow,
@@ -883,7 +1232,7 @@ static int flow_join(struct flow_info * flow,
struct ipcp_info ipcp;
struct layer_info layer;
buffer_t hash;
- buffer_t pbuf = {NULL, 0}; /* nothing to piggyback */
+ buffer_t pbuf = BUF_INIT; /* nothing to piggyback */
int err;
log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
@@ -936,6 +1285,7 @@ static int flow_join(struct flow_info * flow,
goto fail_alloc;
}
+ assert(pbuf.data == NULL && pbuf.len == 0);
assert(err == 0);
freebuf(hash);
@@ -1009,23 +1359,46 @@ static int get_ipcp_by_dst(const char * dst,
static int flow_alloc(struct flow_info * flow,
const char * dst,
+ buffer_t * symmkey,
buffer_t * data,
struct timespec * abstime)
{
- uint8_t buf[MSGBUFSZ];
- buffer_t lpk ={NULL, 0}; /* local public key */
- buffer_t rpk; /* remote public key */
- void * pkp = NULL; /* my public/private key pair */
- uint8_t * s = NULL;
- buffer_t hash;
- int err;
+ struct oap_hdr oap_hdr; /* outgoing request */
+ struct oap_hdr r_oap_hdr; /* incoming response */
+ uint8_t buf[MSGBUFSZ]; /* buffer for local ephkey */
+ buffer_t lpk = BUF_INIT; /* local ephemeral pubkey */
+ void * pkp = NULL; /* ephemeral private key pair */
+ uint8_t * s = NULL; /* symmetric key */
+ void * cpkp = NULL; /* signing private key */
+ void * ccrt = NULL; /* signing certificate */
+ buffer_t hash;
+ uint8_t idbuf[OAP_ID_SIZE];
+ buffer_t id;
+ int err;
+ bool crypt;
+
/* piggyback of user data not yet implemented */
- assert(data != NULL && data->len == 0 && data->data == NULL);
+ assert(data != NULL && BUF_IS_EMPTY(data));
+ assert(symmkey != NULL && BUF_IS_EMPTY(symmkey));
log_info("Allocating flow for %d to %s.", flow->n_pid, dst);
+ if (random_buffer(idbuf, OAP_ID_SIZE) < 0) {
+ log_err("Failed to generate ID.");
+ err = -EIRMD;
+ goto fail_id;
+ }
+
+ id.data = idbuf;
+ id.len = OAP_ID_SIZE;
- if (flow->qs.cypher_s > 0) {
+ if (load_cli_credentials(dst, &cpkp, &ccrt, &crypt) < 0) {
+ log_err("Failed to load security keys for %s.", dst);
+ err = -EAUTH;
+ goto fail_cred;
+ }
+
+ if (crypt > 0) {
ssize_t key_len;
s = malloc(SYMMKEYSZ);
@@ -1048,6 +1421,14 @@ static int flow_alloc(struct flow_info * flow,
log_dbg("Generated ephemeral keys for %d.", flow->n_pid);
}
+ if (oap_hdr_init(id, cpkp, ccrt, lpk, *data, &oap_hdr) < 0) {
+ log_err("Failed to create OAP header.");
+ err = -ENOMEM;
+ goto fail_oap_hdr;
+ }
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_snd(&oap_hdr);
+#endif
if (reg_create_flow(flow) < 0) {
log_err("Failed to create flow.");
err = -EBADF;
@@ -1062,7 +1443,7 @@ static int flow_alloc(struct flow_info * flow,
reg_prepare_flow_alloc(flow);
- if (ipcp_flow_alloc(flow, hash, lpk)) {
+ if (ipcp_flow_alloc(flow, hash, oap_hdr.hdr)) {
log_err("Flow allocation %d failed.", flow->id);
err = -ENOTALLOC;
goto fail_alloc;
@@ -1073,7 +1454,7 @@ static int flow_alloc(struct flow_info * flow,
pthread_cleanup_push(free, hash.data);
pthread_cleanup_push(free, s);
- err = reg_wait_flow_allocated(flow, &rpk, abstime);
+ err = reg_wait_flow_allocated(flow, &r_oap_hdr.hdr, abstime);
pthread_cleanup_pop(false);
pthread_cleanup_pop(false);
@@ -1087,48 +1468,86 @@ static int flow_alloc(struct flow_info * flow,
if (err == -1) {
log_dbg("Flow allocation terminated.");
- err = -EPIPE;
+ err = -EIPCP;
goto fail_alloc;
}
- assert(err == 0);
+ log_dbg("Response received for flow %d to %s.", flow->id, dst);
+
+ if (err < 0) {
+ log_warn("Flow allocation rejected for %s: %d.", dst, err);
+ goto fail_alloc;
+ }
+
+ if (oap_hdr_decode(r_oap_hdr.hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to decode OAP header.");
+ err = -EIPCP;
+ goto fail_r_oap_hdr;
+ }
+#ifdef DEBUG_PROTO_OAP
+ debug_oap_hdr_rcv(&r_oap_hdr);
+#endif
+ if (irm_check_oap_hdr(&r_oap_hdr, flow->mpl) < 0) {
+ log_err("OAP header failed replay check.");
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
- if (flow->qs.cypher_s != 0) { /* crypto requested */
- if (crypt_dh_derive(pkp, rpk, s) < 0) {
+ if (irm_auth_peer(dst, &oap_hdr, &r_oap_hdr) < 0) {
+ log_err("Failed to authenticate %s (flow %d).", dst, flow->id);
+ err = -EAUTH;
+ goto fail_r_oap_hdr;
+ }
+
+ if (lpk.len > 0) { /* crypto requested */
+ if (crypt_dh_derive(pkp, r_oap_hdr.eph, s) < 0) {
log_err("Failed to derive secret for %d.", flow->id);
err = -ECRYPT;
- goto fail_derive;
+ goto fail_r_oap_hdr;
}
crypt_dh_pkp_destroy(pkp);
- freebuf(rpk);
- data->data = s;
- data->len = SYMMKEYSZ;
+
+ symmkey->data = s;
+ symmkey->len = SYMMKEYSZ;
s = NULL;
}
+ oap_hdr_fini(&r_oap_hdr);
+ oap_hdr_fini(&oap_hdr);
+
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+
+ /* TODO: piggyback user data if needed */
+
freebuf(hash);
free(s);
return 0;
- fail_derive:
- freebuf(rpk);
+ fail_r_oap_hdr:
flow->state = FLOW_DEALLOCATED;
+ oap_hdr_fini(&r_oap_hdr);
fail_alloc:
freebuf(hash);
fail_ipcp:
reg_destroy_flow(flow->id);
fail_flow:
- if (flow->qs.cypher_s > 0)
- crypt_dh_pkp_destroy(pkp);
+ oap_hdr_fini(&oap_hdr);
+ fail_oap_hdr:
+ crypt_dh_pkp_destroy(pkp);
fail_pkp:
free(s);
fail_malloc:
+ crypt_free_crt(ccrt);
+ crypt_free_key(cpkp);
+ fail_cred:
+ clrbuf(id);
+ fail_id:
return err;
}
-static int wait_for_accept(enum hash_algo algo,
- const uint8_t * hash)
+static int wait_for_accept(const char * name)
{
struct timespec timeo = TIMESPEC_INIT_MS(IRMD_REQ_ARR_TIMEOUT);
struct timespec abstime;
@@ -1138,25 +1557,23 @@ static int wait_for_accept(enum hash_algo algo,
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- ret = reg_wait_flow_accepting(algo, hash, &abstime);
+ ret = reg_wait_flow_accepting(name, &abstime);
if (ret == -ETIMEDOUT) {
- if (reg_get_exec(algo, hash, &exec) < 0) {
- log_dbg("No program bound to " HASH_FMT32 ".",
- HASH_VAL32(hash));
+ if (reg_get_exec(name, &exec) < 0) {
+ log_dbg("No program bound for %s.", name);
goto fail;
}
- log_info("Autostarting %s.", exec[0]);
-
if (spawn_program(exec) < 0) {
- log_dbg("Failed to autostart " HASH_FMT32 ".",
- HASH_VAL32(hash));
+ log_err("Failed to start %s for %s.", exec[0], name);
goto fail_spawn;
}
+ log_info("Starting %s for %s.", exec[0], name);
+
ts_add(&abstime, &timeo, &abstime);
- ret = reg_wait_flow_accepting(algo, hash, &abstime);
+ ret = reg_wait_flow_accepting(name, &abstime);
if (ret == -ETIMEDOUT)
goto fail_spawn;
@@ -1179,10 +1596,11 @@ static int flow_req_arr(struct flow_info * flow,
struct layer_info layer;
enum hash_algo algo;
int ret;
+ char name[NAME_SIZE + 1];
info.pid = flow->n_1_pid;
- log_info("Flow req arrived from IPCP %d for " HASH_FMT32 ".",
+ log_dbg("Flow req arrived from IPCP %d for " HASH_FMT32 ".",
info.pid, HASH_VAL32(hash));
if (reg_get_ipcp(&info, &layer) < 0) {
@@ -1193,10 +1611,17 @@ static int flow_req_arr(struct flow_info * flow,
algo = (enum hash_algo) layer.dir_hash_algo;
- ret = wait_for_accept(algo, hash);
+ if (reg_get_name_for_hash(name, algo, hash) < 0) {
+ log_warn("No name for " HASH_FMT32 ".", HASH_VAL32(hash));
+ ret = -ENAME;
+ goto fail;
+ }
+
+ log_info("Flow request arrived for %s.", name);
+
+ ret = wait_for_accept(name);
if (ret < 0) {
- log_err("No activeprocess for " HASH_FMT32 ".",
- HASH_VAL32(hash));
+ log_err("No active process for %s.", name);
goto fail;
}
@@ -1218,9 +1643,9 @@ static int flow_alloc_reply(struct flow_info * flow,
int response,
buffer_t * data)
{
- flow->state = response ? FLOW_DEALLOCATED : FLOW_ALLOCATED;
+ flow->state = response != 0 ? FLOW_DEALLOCATED : FLOW_ALLOCATED;
- if (reg_respond_alloc(flow, data) < 0) {
+ if (reg_respond_alloc(flow, data, response) < 0) {
log_err("Failed to reply to flow %d.", flow->id);
flow->state = FLOW_DEALLOCATED;
return -EBADF;
@@ -1232,7 +1657,7 @@ static int flow_alloc_reply(struct flow_info * flow,
static int flow_dealloc(struct flow_info * flow,
struct timespec * ts)
{
- log_info("Deallocating flow %d for process %d (timeout: %zd s).",
+ log_info("Deallocating flow %d for process %d (timeout: %ld s).",
flow->id, flow->n_pid, ts->tv_sec);
reg_dealloc_flow(flow);
@@ -1308,7 +1733,7 @@ static void * acceptloop(void * o)
return (void *) 0;
}
-static void free_msg(void * o)
+static void __cleanup_irm_msg(void * o)
{
irm_msg__free_unpacked((irm_msg_t *) o, NULL);
}
@@ -1327,6 +1752,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
int res;
irm_msg_t * ret_msg;
buffer_t data;
+ buffer_t symmkey = BUF_INIT;;
memset(&flow, 0, sizeof(flow));
@@ -1351,7 +1777,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
ret_msg->code = IRM_MSG_CODE__IRM_REPLY;
- pthread_cleanup_push(free_msg, ret_msg);
+ pthread_cleanup_push(__cleanup_irm_msg, ret_msg);
switch (msg->code) {
case IRM_MSG_CODE__IRM_CREATE_IPCP:
@@ -1380,7 +1806,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
res = disconnect_ipcp(msg->pid, msg->dst, msg->comp);
break;
case IRM_MSG_CODE__IRM_BIND_PROGRAM:
- /* Make exec NULL terminated instead of empty string terminated */
+ /* Terminate with NULL instead of "" */
free(msg->exec[msg->n_exec - 1]);
msg->exec[msg->n_exec - 1] = NULL;
res = bind_program(msg->exec, msg->name, msg->opts);
@@ -1406,8 +1832,7 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
res = list_ipcps(&ret_msg->ipcps, &ret_msg->n_ipcps);
break;
case IRM_MSG_CODE__IRM_CREATE_NAME:
- strcpy(name.name, msg->names[0]->name);
- name.pol_lb = msg->names[0]->pol_lb;
+ name = name_info_msg_to_s(msg->name_info);
res = name_create(&name);
break;
case IRM_MSG_CODE__IRM_DESTROY_NAME:
@@ -1423,17 +1848,21 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
res = name_unreg(msg->name, msg->pid);
break;
case IRM_MSG_CODE__IRM_FLOW_ACCEPT:
+ tpm_wait_work(irmd.tpm);
data.len = msg->pk.len;
data.data = msg->pk.data;
msg->has_pk = false;
assert(data.len > 0 ? data.data != NULL : data.data == NULL);
flow = flow_info_msg_to_s(msg->flow_info);
- res = flow_accept(&flow, &data, abstime);
+ res = flow_accept(&flow, &symmkey, &data, abstime);
if (res == 0) {
ret_msg->flow_info = flow_info_s_to_msg(&flow);
- ret_msg->has_symmkey = data.len != 0;
- ret_msg->symmkey.data = data.data;
- ret_msg->symmkey.len = data.len;
+ ret_msg->has_symmkey = symmkey.len != 0;
+ ret_msg->symmkey.data = symmkey.data;
+ ret_msg->symmkey.len = symmkey.len;
+ ret_msg->has_pk = data.len != 0;
+ ret_msg->pk.data = data.data;
+ ret_msg->pk.len = data.len;
}
break;
case IRM_MSG_CODE__IRM_FLOW_ALLOC:
@@ -1443,12 +1872,15 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg)
assert(data.len > 0 ? data.data != NULL : data.data == NULL);
flow = flow_info_msg_to_s(msg->flow_info);
abstime = abstime == NULL ? &max : abstime;
- res = flow_alloc(&flow, msg->dst, &data, abstime);
+ res = flow_alloc(&flow, msg->dst, &symmkey, &data, abstime);
if (res == 0) {
ret_msg->flow_info = flow_info_s_to_msg(&flow);
- ret_msg->has_symmkey = data.len != 0;
- ret_msg->symmkey.data = data.data;
- ret_msg->symmkey.len = data.len;
+ ret_msg->has_symmkey = symmkey.len != 0;
+ ret_msg->symmkey.data = symmkey.data;
+ ret_msg->symmkey.len = symmkey.len;
+ ret_msg->has_pk = data.len != 0;
+ ret_msg->pk.data = data.data;
+ ret_msg->pk.len = data.len;
}
break;
case IRM_MSG_CODE__IRM_FLOW_JOIN:
@@ -1540,10 +1972,10 @@ static void * mainloop(void * o)
continue;
}
- tpm_dec(irmd.tpm);
+ tpm_begin_work(irmd.tpm);
pthread_cleanup_push(__cleanup_close_ptr, &sfd);
- pthread_cleanup_push(free_msg, msg);
+ pthread_cleanup_push(__cleanup_irm_msg, msg);
ret_msg = do_command_msg(msg);
@@ -1556,12 +1988,12 @@ static void * mainloop(void * o)
}
if (ret_msg->result == -EPIPE) {
- log_dbg("Terminated command: application closed socket.");
+ log_dbg("Terminated command: remote closed socket.");
goto fail;
}
if (ret_msg->result == -EIRMD) {
- log_dbg("Terminated command: IRMd not in running state.");
+ log_dbg("Terminated command: IRMd not running.");
goto fail;
}
@@ -1596,54 +2028,20 @@ static void * mainloop(void * o)
pthread_cleanup_pop(true);
pthread_cleanup_pop(true);
- tpm_inc(irmd.tpm);
+ tpm_end_work(irmd.tpm);
continue;
fail:
irm_msg__free_unpacked(ret_msg, NULL);
fail_msg:
close(sfd);
- tpm_inc(irmd.tpm);
+ tpm_end_work(irmd.tpm);
continue;
}
return (void *) 0;
}
-static void irm_fini(void)
-{
-#ifdef HAVE_FUSE
- struct timespec wait = TIMESPEC_INIT_MS(1);
- int retries = 5;
-#endif
- if (irmd_get_state() != IRMD_NULL)
- log_warn("Unsafe destroy.");
-
- tpm_destroy(irmd.tpm);
-
- close(irmd.sockfd);
-
- if (unlink(IRM_SOCK_PATH))
- log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
-
- if (irmd.rdrb != NULL)
- shm_rdrbuff_destroy(irmd.rdrb);
-
- if (irmd.lf != NULL)
- lockfile_destroy(irmd.lf);
-
- pthread_mutex_destroy(&irmd.cmd_lock);
- pthread_cond_destroy(&irmd.cmd_cond);
- pthread_rwlock_destroy(&irmd.state_lock);
-
-#ifdef HAVE_FUSE
- while (rmdir(FUSE_PREFIX) < 0 && retries-- > 0)
- nanosleep(&wait, NULL);
- if (retries < 0)
- log_err("Failed to remove " FUSE_PREFIX);
-#endif
-}
-
#ifdef HAVE_FUSE
static void destroy_mount(char * mnt)
{
@@ -1719,6 +2117,79 @@ void * irm_sanitize(void * o)
return (void *) 0;
}
+static int irm_load_store(char * dpath)
+{
+ struct stat st;
+ struct dirent * dent;
+ DIR * dir;
+ void * crt;
+
+ if (stat(dpath, &st) == -1) {
+ log_dbg("Store directory %s not found.", dpath);
+ return 0;
+ }
+
+ if (!S_ISDIR(st.st_mode)) {
+ log_err("%s is not a directory.", dpath);
+ goto fail_dir;
+ }
+
+ /* loop through files in directory and load certificates */
+ dir = opendir(dpath);
+ if (dir == NULL) {
+ log_err("Failed to open %s.", dpath);
+ goto fail_dir;
+ }
+
+ while ((dent = readdir(dir)) != NULL) {
+ char path[NAME_PATH_SIZE + 1];
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ snprintf(path, sizeof(path), "%s/%s", dpath,
+ dent->d_name);
+
+ if (stat(path, &st) == -1) {
+ log_dbg("Failed to stat %s.", path);
+ continue;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ log_dbg("%s is not a regular file.", path);
+ goto fail_file;
+ }
+
+ if (crypt_load_crt_file(path, &crt) < 0) {
+ log_err("Failed to load certificate from %s.", path);
+ goto fail_file;
+ }
+
+ if (auth_add_crt_to_store(irmd.auth.ctx, crt) < 0) {
+ log_err("Failed to add certificate from %s to store.",
+ path);
+ goto fail_crt_add;
+ }
+
+ log_dbg("Loaded certificate: %s.", path);
+
+ crypt_free_crt(crt);
+ }
+
+ closedir(dir);
+
+ log_info("Loaded certificates from %s.", dpath);
+
+ return 0;
+
+ fail_crt_add:
+ crypt_free_crt(crt);
+ fail_file:
+ closedir(dir);
+ fail_dir:
+ return -1;
+}
static int irm_init(void)
{
@@ -1819,6 +2290,30 @@ static int irm_init(void)
log_err("Failed to greate thread pool.");
goto fail_tpm_create;
}
+
+ if (pthread_mutex_init(&irmd.auth.mtx, NULL) < 0) {
+ log_err("Failed to initialize auth mutex.");
+ goto fail_auth_mtx;
+ }
+
+ irmd.auth.ctx = auth_create_ctx();
+ if (irmd.auth.ctx == NULL) {
+ log_err("Failed to create auth store context.");
+ goto fail_auth_ctx;
+ }
+
+ list_head_init(&irmd.auth.list);
+
+ if (irm_load_store(OUROBOROS_CA_CRT_DIR) < 0) {
+ log_err("Failed to load CA certificates.");
+ goto fail_auth_ctx;
+ }
+
+ if (irm_load_store(OUROBOROS_CHAIN_DIR) < 0) {
+ log_err("Failed to load intermediate certificates.");
+ goto fail_auth_ctx;
+ }
+
#ifdef HAVE_FUSE
mask = umask(0);
@@ -1844,6 +2339,8 @@ static int irm_init(void)
gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
#endif
+ irmd_set_state(IRMD_INIT);
+
return 0;
#ifdef HAVE_LIBGCRYPT
@@ -1851,8 +2348,12 @@ static int irm_init(void)
#ifdef HAVE_FUSE
rmdir(FUSE_PREFIX);
#endif
- tpm_destroy(irmd.tpm);
+ auth_destroy_ctx(irmd.auth.ctx);
#endif
+ fail_auth_ctx:
+ pthread_mutex_destroy(&irmd.auth.mtx);
+ fail_auth_mtx:
+ tpm_destroy(irmd.tpm);
fail_tpm_create:
shm_rdrbuff_destroy(irmd.rdrb);
fail_rdrbuff:
@@ -1872,6 +2373,69 @@ static int irm_init(void)
return -1;
}
+static void irm_fini(void)
+{
+ struct list_head * p;
+ struct list_head * h;
+#ifdef HAVE_FUSE
+ struct timespec wait = TIMESPEC_INIT_MS(1);
+ int retries = 5;
+#endif
+ if (irmd_get_state() != IRMD_INIT)
+ log_warn("Unsafe destroy.");
+
+ pthread_mutex_lock(&irmd.auth.mtx);
+
+ list_for_each_safe(p, h, &irmd.auth.list) {
+ struct oaph * oaph = list_entry(p, struct oaph, next);
+ list_del(&oaph->next);
+ free(oaph);
+ }
+
+ pthread_mutex_unlock(&irmd.auth.mtx);
+ pthread_mutex_destroy(&irmd.auth.mtx);
+
+ auth_destroy_ctx(irmd.auth.ctx);
+
+ tpm_destroy(irmd.tpm);
+
+ close(irmd.sockfd);
+
+ if (unlink(IRM_SOCK_PATH))
+ log_dbg("Failed to unlink %s.", IRM_SOCK_PATH);
+
+ if (irmd.rdrb != NULL)
+ shm_rdrbuff_destroy(irmd.rdrb);
+
+ if (irmd.lf != NULL)
+ lockfile_destroy(irmd.lf);
+
+ pthread_mutex_lock(&irmd.cmd_lock);
+
+ list_for_each_safe(p, h, &irmd.cmds) {
+ struct cmd * cmd = list_entry(p, struct cmd, next);
+ list_del(&cmd->next);
+ close(cmd->fd);
+ free(cmd);
+ }
+
+ pthread_mutex_unlock(&irmd.cmd_lock);
+
+ pthread_mutex_destroy(&irmd.cmd_lock);
+ pthread_cond_destroy(&irmd.cmd_cond);
+ pthread_rwlock_destroy(&irmd.state_lock);
+
+#ifdef HAVE_FUSE
+ while (rmdir(FUSE_PREFIX) < 0 && retries-- > 0)
+ nanosleep(&wait, NULL);
+ if (retries < 0)
+ log_err("Failed to remove " FUSE_PREFIX);
+#endif
+ assert(list_is_empty(&irmd.cmds));
+
+ irmd.state = IRMD_NULL;
+}
+
static void usage(void)
{
printf("Usage: irmd \n"
@@ -1885,11 +2449,11 @@ static void usage(void)
static int irm_start(void)
{
+ irmd_set_state(IRMD_RUNNING);
+
if (tpm_start(irmd.tpm))
goto fail_tpm_start;
- irmd_set_state(IRMD_RUNNING);
-
if (pthread_create(&irmd.irm_sanitize, NULL, irm_sanitize, NULL))
goto fail_irm_sanitize;
@@ -1904,9 +2468,9 @@ static int irm_start(void)
pthread_cancel(irmd.irm_sanitize);
pthread_join(irmd.irm_sanitize, NULL);
fail_irm_sanitize:
- irmd_set_state(IRMD_NULL);
tpm_stop(irmd.tpm);
fail_tpm_start:
+ irmd_set_state(IRMD_INIT);
return -1;
}
@@ -1947,7 +2511,7 @@ static void irm_stop(void)
tpm_stop(irmd.tpm);
- irmd_set_state(IRMD_NULL);
+ irmd_set_state(IRMD_INIT);
}
static void irm_argparse(int argc,
@@ -1998,8 +2562,8 @@ static void * kill_dash_nine(void * o)
slept += intv;
}
- log_dbg("I am become Death, destroyer of hung processes.");
-
+ log_dbg("I guess I’ll have to shut you down for good this time,");
+ log_dbg("already tried a SIGQUIT, so now it’s KILL DASH 9.");
#ifdef IRMD_KILL_ALL_PROCESSES
reg_kill_all_proc(SIGKILL);
nanosleep(&ts, NULL);
@@ -2058,7 +2622,7 @@ int main(int argc,
if (geteuid() != 0) {
printf("IPC Resource Manager must be run as root.\n");
- exit(EXIT_FAILURE);
+ goto fail_irm_init;
}
if (irm_init() < 0)
@@ -2076,7 +2640,7 @@ int main(int argc,
#ifdef HAVE_TOML
if (irm_configure(irmd.cfg_file) < 0) {
- irmd_set_state(IRMD_NULL);
+ irmd_set_state(IRMD_SHUTDOWN);
ret = EXIT_FAILURE;
}
#endif
diff --git a/src/irmd/oap.c b/src/irmd/oap.c
new file mode 100644
index 00000000..500da6f1
--- /dev/null
+++ b/src/irmd/oap.c
@@ -0,0 +1,288 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros flow allocation protocol header
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#if defined(__linux__) || defined(__CYGWIN__)
+ #define _DEFAULT_SOURCE
+#else
+ #define _POSIX_C_SOURCE 200809L
+#endif
+
+#define OUROBOROS_PREFIX "irmd/oap"
+
+#include <ouroboros/crypt.h>
+#include <ouroboros/endian.h>
+#include <ouroboros/logs.h>
+#include <ouroboros/rib.h>
+#include <ouroboros/time.h>
+
+#include "config.h"
+
+#include "oap.h"
+
+#include <assert.h>
+
+int oap_hdr_init(buffer_t id,
+ void * pkp,
+ void * pubcrt,
+ buffer_t ephkey,
+ buffer_t data,
+ struct oap_hdr * oap_hdr)
+{
+ struct timespec now;
+ uint64_t stamp;
+ buffer_t hdr;
+ buffer_t der = BUF_INIT;
+ buffer_t sig = BUF_INIT;
+ buffer_t sign;
+ uint16_t len;
+ off_t offset;
+
+ assert(id.data != NULL && id.len == OAP_ID_SIZE);
+ assert(oap_hdr != NULL);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ stamp = hton64(TS_TO_UINT64(now));
+
+ if (pubcrt != NULL && crypt_crt_der(pubcrt, &der) < 0)
+ goto fail_der;
+
+ hdr.len = id.len +
+ sizeof(stamp) +
+ sizeof(len) + der.len +
+ sizeof(len) + ephkey.len +
+ sizeof(len) + data.len +
+ sizeof(len); /* sig len */
+
+ hdr.data = malloc(hdr.len);
+ if (hdr.data == NULL)
+ goto fail_hdr;
+
+ offset = 0;
+
+ memcpy(hdr.data, id.data, id.len);
+ offset += id.len;
+
+ memcpy(hdr.data + offset, &stamp, sizeof(stamp));
+ offset += sizeof(stamp);
+
+ /* pubcrt */
+ len = hton16((uint16_t) der.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (der.len != 0)
+ memcpy(hdr.data + offset, der.data, der.len);
+ offset += der.len;
+
+ /* ephkey */
+ len = hton16((uint16_t) ephkey.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (ephkey.len != 0)
+ memcpy(hdr.data + offset, ephkey.data, ephkey.len);
+ offset += ephkey.len;
+
+ /* data */
+ len = hton16((uint16_t) data.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+ if (data.len != 0)
+ memcpy(hdr.data + offset, data.data, data.len);
+ offset += data.len;
+
+ sign.data = hdr.data;
+ sign.len = hdr.len - sizeof(len);
+
+ if (pkp != NULL && auth_sign(pkp, sign, &sig) < 0)
+ goto fail_sig;
+
+ len = hton16((uint16_t) sig.len);
+ memcpy(hdr.data + offset, &len, sizeof(len));
+ offset += sizeof(len);
+
+ oap_hdr->hdr = hdr;
+
+ assert((size_t) offset == hdr.len);
+
+ if (sig.len > 0) {
+ oap_hdr->hdr.len += sig.len;
+ oap_hdr->hdr.data = realloc(hdr.data, oap_hdr->hdr.len);
+ if (oap_hdr->hdr.data == NULL)
+ goto fail_oap_hdr;
+
+ memcpy(oap_hdr->hdr.data + offset, sig.data, sig.len);
+ clrbuf(hdr);
+ }
+
+ if (oap_hdr_decode(oap_hdr->hdr, oap_hdr) < 0)
+ goto fail_decode;
+
+ freebuf(der);
+ freebuf(sig);
+
+ return 0;
+
+ fail_decode:
+ oap_hdr_fini(oap_hdr);
+ fail_oap_hdr:
+ freebuf(sig);
+ fail_sig:
+ freebuf(hdr);
+ fail_hdr:
+ freebuf(der);
+ fail_der:
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+ return -1;
+}
+
+void oap_hdr_fini(struct oap_hdr * oap_hdr)
+{
+ assert(oap_hdr != NULL);
+
+ freebuf(oap_hdr->hdr);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+}
+
+int oap_hdr_decode(buffer_t hdr,
+ struct oap_hdr * oap_hdr)
+{
+ off_t offset;
+
+ assert(oap_hdr != NULL);
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+
+ if (hdr.len < OAP_HDR_MIN_SIZE)
+ goto fail_decode;
+
+ oap_hdr->id.data = hdr.data;
+ oap_hdr->id.len = OAP_ID_SIZE;
+
+ offset = OAP_ID_SIZE;
+
+ oap_hdr->timestamp = ntoh64(*(uint64_t *)(hdr.data + offset));
+
+ offset += sizeof(uint64_t);
+
+ oap_hdr->crt.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->crt.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->crt.len;
+
+ if ((size_t) offset + sizeof(uint16_t) >= hdr.len)
+ goto fail_decode;
+
+ oap_hdr->eph.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->eph.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->eph.len;
+
+ if ((size_t) offset + sizeof(uint16_t) >= hdr.len)
+ goto fail_decode;
+
+ oap_hdr->data.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->data.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->data.len;
+
+ if ((size_t) offset + sizeof(uint16_t) > hdr.len)
+ goto fail_decode;
+
+ oap_hdr->sig.len = (size_t) ntoh16(*(uint16_t *)(hdr.data + offset));
+ oap_hdr->sig.data = hdr.data + offset + sizeof(uint16_t);
+
+ offset += sizeof(uint16_t) + oap_hdr->sig.len;
+
+ if ((size_t) offset != hdr.len)
+ goto fail_decode;
+
+ oap_hdr->hdr = hdr;
+
+ return 0;
+
+ fail_decode:
+ memset(oap_hdr, 0, sizeof(*oap_hdr));
+ return -1;
+}
+
+#ifdef DEBUG_PROTO_OAP
+static void debug_oap_hdr(const struct oap_hdr * hdr)
+{
+ assert(hdr);
+
+ if (hdr->crt.len > 0)
+ log_proto(" Certificate: [%zu bytes]", hdr->crt.len);
+ else
+ log_proto(" Certificate: <none>");
+
+ if (hdr->eph.len > 0)
+ log_proto(" Ephemeral Public Key: [%zu bytes]", hdr->eph.len);
+ else
+ log_proto(" Ephemeral Public Key: <none>");
+ if (hdr->data.len > 0)
+ log_proto(" Data: [%zu bytes]", hdr->data.len);
+ else
+ log_proto(" Data: <none>");
+ if (hdr->sig.len > 0)
+ log_proto(" Signature: [%zu bytes]", hdr->sig.len);
+ else
+ log_proto(" Signature: <none>");
+}
+
+void debug_oap_hdr_rcv(const struct oap_hdr * hdr)
+{
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ time_t stamp;
+
+ assert(hdr);
+
+ stamp = (time_t) hdr->timestamp / BILLION;
+
+ tm = gmtime(&stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+
+ log_proto("OAP_HDR [" HASH_FMT64 " @ %s ] <--",
+ HASH_VAL64(hdr->id.data), tmstr);
+
+ debug_oap_hdr(hdr);
+}
+
+void debug_oap_hdr_snd(const struct oap_hdr * hdr)
+{
+ struct tm * tm;
+ char tmstr[RIB_TM_STRLEN];
+ time_t stamp;
+
+ assert(hdr);
+
+ stamp = (time_t) hdr->timestamp / BILLION;
+
+ tm = gmtime(&stamp);
+ strftime(tmstr, sizeof(tmstr), RIB_TM_FORMAT, tm);
+
+ log_proto("OAP_HDR [" HASH_FMT64 " @ %s ] -->",
+ HASH_VAL64(hdr->id.data), tmstr);
+
+ debug_oap_hdr(hdr);
+}
+#endif
+
diff --git a/src/irmd/oap.h b/src/irmd/oap.h
new file mode 100644
index 00000000..ccdfa804
--- /dev/null
+++ b/src/irmd/oap.h
@@ -0,0 +1,94 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Ouroboros flow allocation protocol header
+ *
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#ifndef OUROBOROS_IRMD_OAP_H
+#define OUROBOROS_IRMD_OAP_H
+
+#include <ouroboros/utils.h>
+
+#define OAP_ID_SIZE (16)
+#define OAP_HDR_MIN_SIZE (OAP_ID_SIZE + sizeof(uint64_t) + 4 * sizeof(uint16_t))
+
+
+/*
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +---------------------------------------------------------------+
+ * | |
+ * | id (128 bits) |
+ * | |
+ * | |
+ * +---------------------------------------------------------------+
+ * | timestamp (64 bits) |
+ * | |
+ * +---------------------------------------------------------------+
+ * | crt_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | certificate |
+ * | |
+ * +---------------------------------------------------------------+
+ * | eph_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | public key for ECDHE |
+ * | |
+ * +---------------------------------------------------------------+
+ * | data_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | piggy backed application data |
+ * | |
+ * +---------------------------------------------------------------+
+ * | sig_len (16 bits) | |
+ * +-----------+-----------------+ |
+ * | signature |
+ * | |
+ * +---------------------------------------------------------------+
+ */
+
+struct oap_hdr {
+ uint64_t timestamp;
+ buffer_t id;
+ buffer_t crt;
+ buffer_t eph;
+ buffer_t data;
+ buffer_t sig;
+ buffer_t hdr;
+};
+
+int oap_hdr_init(buffer_t id,
+ void * pkp,
+ void * pubcrt,
+ buffer_t ephkey,
+ buffer_t data,
+ struct oap_hdr * oap_hdr);
+
+void oap_hdr_fini(struct oap_hdr * oap_hdr);
+
+int oap_hdr_decode(buffer_t hdr,
+ struct oap_hdr * oap_hdr);
+
+#ifdef DEBUG_PROTO_OAP
+void debug_oap_hdr_snd(const struct oap_hdr * hdr);
+
+void debug_oap_hdr_rcv(const struct oap_hdr * hdr);
+#endif /* DEBUG_PROTO_OAP */
+
+#endif /* OUROBOROS_IRMD_OAP_H */
diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h
index 75ada971..d1e4811c 100644
--- a/src/irmd/reg/flow.h
+++ b/src/irmd/reg/flow.h
@@ -25,6 +25,7 @@
#include <ouroboros/list.h>
#include <ouroboros/flow.h>
+#include <ouroboros/name.h>
#include <ouroboros/pthread.h>
#include <ouroboros/qos.h>
#include <ouroboros/shm_rbuff.h>
@@ -34,12 +35,15 @@
#include <time.h>
struct reg_flow {
- struct list_head next;
+ struct list_head next;
- struct flow_info info;
+ struct flow_info info;
+ int response;
- buffer_t data;
- struct timespec t0;
+ buffer_t data;
+ struct timespec t0;
+
+ char name[NAME_SIZE + 1];
struct shm_rbuff * n_rb;
struct shm_rbuff * n_1_rb;
diff --git a/src/irmd/reg/ipcp.c b/src/irmd/reg/ipcp.c
index 6580cb5b..474527a4 100644
--- a/src/irmd/reg/ipcp.c
+++ b/src/irmd/reg/ipcp.c
@@ -40,7 +40,7 @@ struct reg_ipcp * reg_ipcp_create(const struct ipcp_info * info)
struct reg_ipcp * ipcp;
assert(info != NULL);
- assert(info->state == IPCP_BOOT);
+ assert(info->state == IPCP_INIT);
ipcp = malloc(sizeof(*ipcp));
if (ipcp == NULL) {
@@ -54,7 +54,7 @@ struct reg_ipcp * reg_ipcp_create(const struct ipcp_info * info)
list_head_init(&ipcp->next);
ipcp->info = *info;
- ipcp->info.state = IPCP_BOOT;
+ ipcp->info.state = IPCP_INIT;
strcpy(ipcp->layer.name, "Not enrolled.");
@@ -77,7 +77,7 @@ void reg_ipcp_update(struct reg_ipcp * ipcp,
const struct ipcp_info * info)
{
assert(ipcp != NULL);
- assert(info->state != IPCP_INIT);
+ assert(info->state != IPCP_NULL);
ipcp->info = *info;
}
@@ -86,7 +86,7 @@ void reg_ipcp_set_layer(struct reg_ipcp * ipcp,
const struct layer_info * info)
{
assert(ipcp != NULL);
- assert(ipcp->info.state == IPCP_OPERATIONAL);
+ assert(ipcp->info.state == IPCP_BOOT);
ipcp->layer = *info;
}
diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c
index 1ac939a5..4e609711 100644
--- a/src/irmd/reg/name.c
+++ b/src/irmd/reg/name.c
@@ -66,15 +66,14 @@ struct reg_name * reg_name_create(const struct name_info * info)
goto fail_malloc;
}
+ memset(name, 0, sizeof(*name));
+
list_head_init(&name->next);
- list_head_init(&name->progs);
- list_head_init(&name->procs);
- list_head_init(&name->active);
+ list_head_init(&name->progs.list);
+ list_head_init(&name->procs.list);
+ list_head_init(&name->active.list);
- name->info = *info;
- name->n_progs = 0;
- name->n_procs = 0;
- name->n_active = 0;
+ name->info = *info;
return name;
@@ -88,13 +87,13 @@ void reg_name_destroy(struct reg_name * name)
assert(list_is_empty(&name->next));
- assert(name->n_progs == 0);
- assert(name->n_procs == 0);
- assert(name->n_active == 0);
+ assert(name->progs.len == 0);
+ assert(name->procs.len == 0);
+ assert(name->active.len == 0);
- assert(list_is_empty(&name->progs));
- assert(list_is_empty(&name->procs));
- assert(list_is_empty(&name->active));
+ assert(list_is_empty(&name->progs.list));
+ assert(list_is_empty(&name->procs.list));
+ assert(list_is_empty(&name->active.list));
free(name);
}
@@ -107,7 +106,7 @@ static struct proc_entry * __reg_name_get_active(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->active) {
+ list_for_each(p, &name->active.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -123,13 +122,13 @@ static void __reg_name_del_all_active(struct reg_name * name,
struct list_head * p;
struct list_head * h;
- list_for_each_safe(p, h, &name->active) {
+ list_for_each_safe(p, h, &name->active.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid) {
list_del(&entry->next);
free(entry);
- name->n_active--;
+ --name->active.len;
}
}
}
@@ -142,7 +141,7 @@ static struct proc_entry * __reg_name_get_proc(const struct reg_name * name,
assert(name != NULL);
assert(pid > 0);
- list_for_each(p, &name->procs) {
+ list_for_each(p, &name->procs.list) {
struct proc_entry * entry;
entry = list_entry(p, struct proc_entry, next);
if (entry->pid == pid)
@@ -160,7 +159,7 @@ static struct prog_entry * __reg_name_get_prog(const struct reg_name * name,
assert(name != NULL);
assert(prog != NULL);
- list_for_each(p, &name->progs) {
+ list_for_each(p, &name->progs.list) {
struct prog_entry * entry;
entry = list_entry(p, struct prog_entry, next);
if (strcmp(entry->exec[0], prog) == 0)
@@ -195,16 +194,16 @@ int reg_name_add_active(struct reg_name * name,
switch (name->info.pol_lb) {
case LB_RR: /* Round robin policy. */
- list_add_tail(&entry->next, &name->active);
+ list_add_tail(&entry->next, &name->active.list);
break;
case LB_SPILL: /* Keep accepting flows on the current process */
- list_add(&entry->next, &name->active);
+ list_add(&entry->next, &name->active.list);
break;
default:
goto fail_unreachable;
}
- name->n_active++;
+ ++name->active.len;
return 0;
@@ -226,19 +225,23 @@ void reg_name_del_active(struct reg_name * name,
list_del(&entry->next);
- name->n_active--;
+ --name->active.len;
free(entry);
}
pid_t reg_name_get_active(struct reg_name * name)
{
+ struct proc_entry * e;
+
assert(name != NULL);
- if (list_is_empty(&name->active))
+ if (list_is_empty(&name->active.list))
return -1;
- return list_first_entry(&name->active, struct proc_entry, next)->pid;
+ e = list_first_entry(&name->active.list, struct proc_entry, next);
+
+ return e->pid;
}
int reg_name_add_proc(struct reg_name * name,
@@ -259,9 +262,9 @@ int reg_name_add_proc(struct reg_name * name,
entry->pid = pid;
- list_add(&entry->next, &name->procs);
+ list_add(&entry->next, &name->procs.list);
- name->n_procs++;
+ ++name->procs.len;
return 0;
@@ -287,7 +290,7 @@ void reg_name_del_proc(struct reg_name * name,
free(entry);
- name->n_procs--;
+ --name->procs.len;
assert(__reg_name_get_proc(name, pid) == NULL);
}
@@ -296,8 +299,7 @@ bool reg_name_has_proc(const struct reg_name * name,
pid_t pid)
{
return __reg_name_get_proc(name, pid) != NULL;
-} char ** exec;
-
+}
int reg_name_add_prog(struct reg_name * name,
char ** exec)
@@ -322,11 +324,11 @@ int reg_name_add_prog(struct reg_name * name,
goto fail_exec;
}
- list_add(&entry->next, &name->progs);
+ list_add(&entry->next, &name->progs.list);
log_dbg("Add prog %s to name %s.", exec[0], name->info.name);
- name->n_progs++;
+ ++name->progs.len;
return 0;
@@ -352,7 +354,7 @@ void reg_name_del_prog(struct reg_name * name,
__free_prog_entry(entry);
- name->n_progs--;
+ --name->progs.len;
assert(__reg_name_get_prog(name, prog) == NULL);
}
@@ -368,8 +370,12 @@ bool reg_name_has_prog(const struct reg_name * name,
char ** reg_name_get_exec(const struct reg_name * name)
{
- if (list_is_empty(&name->progs))
+ struct prog_entry * e;
+
+ if (list_is_empty(&name->progs.list))
return NULL;
- return list_first_entry(&name->progs, struct prog_entry, next)->exec;
+ e = list_first_entry(&name->progs.list, struct prog_entry, next);
+
+ return e->exec;
}
diff --git a/src/irmd/reg/name.h b/src/irmd/reg/name.h
index 97ca7f04..30a64e1c 100644
--- a/src/irmd/reg/name.h
+++ b/src/irmd/reg/name.h
@@ -33,14 +33,25 @@ struct reg_name {
struct name_info info;
- struct list_head progs; /* autostart programs for this name */
- size_t n_progs; /* number of programs */
-
- struct list_head procs; /* processes bound to this name */
- size_t n_procs; /* number of processes */
-
- struct list_head active; /* processes actively calling accept */
- size_t n_active; /* number of processes accepting */
+ struct {
+ void * key;
+ void * crt;
+ } cache;
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } progs; /* autostart programs for this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } procs; /* processes bound to this name */
+
+ struct {
+ struct list_head list;
+ size_t len;
+ } active; /* processes actively calling accept */
};
struct reg_name * reg_name_create(const struct name_info * info);
@@ -74,5 +85,4 @@ pid_t reg_name_get_active(struct reg_name * name);
void reg_name_del_active(struct reg_name * name,
pid_t proc);
-
#endif /* OUROBOROS_IRMD_REG_NAME_H */
diff --git a/src/irmd/reg/proc.h b/src/irmd/reg/proc.h
index 99f74fef..499ecc72 100644
--- a/src/irmd/reg/proc.h
+++ b/src/irmd/reg/proc.h
@@ -32,8 +32,8 @@ struct reg_proc {
struct proc_info info;
- struct list_head names; /* names for which process accepts flows */
- size_t n_names; /* number of names */
+ struct list_head names; /* process accepts flows for names */
+ size_t n_names; /* number of names */
struct shm_flow_set * set;
};
diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c
index d95a4722..a24a9d1d 100644
--- a/src/irmd/reg/reg.c
+++ b/src/irmd/reg/reg.c
@@ -28,6 +28,7 @@ The IPC Resource Manager - Registry
#include <ouroboros/errno.h>
#include <ouroboros/list.h>
#include <ouroboros/logs.h>
+#include <ouroboros/protobuf.h>
#include <ouroboros/pthread.h>
#include "reg.h"
@@ -46,6 +47,7 @@ The IPC Resource Manager - Registry
struct {
struct bmp * flow_ids; /* flow_ids for flows */
+
struct list_head flows; /* flow information */
size_t n_flows; /* number of flows */
@@ -151,16 +153,23 @@ static struct reg_ipcp * __reg_get_ipcp_by_layer(const char * layer)
return NULL;
}
-static struct list_head * __reg_after_ipcp(pid_t pid)
+
+static struct list_head * __reg_after_ipcp(const struct ipcp_info * info)
{
struct list_head * p;
- assert(pid > 0);
+ assert(info != NULL);
list_for_each(p, &reg.ipcps) {
struct reg_ipcp * entry;
entry = list_entry(p, struct reg_ipcp, next);
- if (entry->info.pid > pid)
+ if (entry->info.type < info->type)
+ continue;
+
+ if (entry->info.type > info->type)
+ break;
+
+ if (entry->info.pid > info->pid)
break;
}
@@ -183,41 +192,17 @@ static struct reg_name * __reg_get_name(const char * name)
return NULL;
}
-static struct reg_name * __reg_get_name_by_hash(enum hash_algo algo,
- const uint8_t * hash)
-{
- struct list_head * p;
- uint8_t * thash;
- size_t len;
-
- len = hash_len(algo);
-
- thash = malloc(len);
- if (thash == NULL)
- return NULL;
-
- list_for_each(p, &reg.names) {
- struct reg_name * n = list_entry(p, struct reg_name, next);
- str_hash(algo, thash, n->info.name);
- if (memcmp(thash, hash, len) == 0) {
- free(thash);
- return n;
- }
- }
-
- free(thash);
-
- return NULL;
-}
-
-static int __reg_get_pending_flow_id_for_hash(enum hash_algo algo,
- const uint8_t * hash)
+static int __reg_get_pending_flow_id(const char * name)
{
struct reg_name * entry;
struct reg_flow * flow;
pid_t pid;
- entry =__reg_get_name_by_hash(algo, hash);
+ assert(name != NULL);
+ assert(strlen(name) > 0);
+ assert(strlen(name) < NAME_SIZE + 1);
+
+ entry =__reg_get_name(name);
if (entry == NULL)
return -ENAME;
@@ -226,7 +211,10 @@ static int __reg_get_pending_flow_id_for_hash(enum hash_algo algo,
return -EAGAIN;
flow = __reg_get_accept_flow(pid);
- assert(flow != NULL);
+ if (flow == NULL) /* compiler barks, this can't be NULL */
+ return -EAGAIN;
+
+ strcpy(flow->name, name);
return flow->info.id;
}
@@ -388,30 +376,17 @@ static struct reg_prog * __reg_get_prog(const char * name)
return NULL;
}
-static char ** __reg_get_exec(enum hash_algo algo,
- const uint8_t * hash)
+static char ** __reg_get_exec(const char * name)
{
struct list_head * p;
- uint8_t * buf;
-
- buf = malloc(hash_len(algo));
- if (buf == NULL) {
- log_err("Failed to malloc hash buffer.");
- return NULL;
- }
list_for_each(p, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
- str_hash(algo, buf, entry->info.name);
- if (memcmp(buf, hash, hash_len(algo)) == 0) {
- free(buf);
+ if (strcmp(entry->info.name, name) == 0)
return reg_name_get_exec(entry);
- }
}
- free(buf);
-
return NULL;
}
@@ -614,6 +589,14 @@ void reg_clear(void)
reg.n_procs--;
}
+ list_for_each_safe(p, h, &reg.flows) {
+ struct reg_flow * entry;
+ entry = list_entry(p, struct reg_flow, next);
+ list_del(&entry->next);
+ reg_flow_destroy(entry);
+ reg.n_flows--;
+ }
+
list_for_each_safe(p, h, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
@@ -630,14 +613,6 @@ void reg_clear(void)
reg.n_ipcps--;
}
- list_for_each_safe(p, h, &reg.flows) {
- struct reg_flow * entry;
- entry = list_entry(p, struct reg_flow, next);
- list_del(&entry->next);
- reg_flow_destroy(entry);
- reg.n_flows--;
- }
-
pthread_mutex_unlock(&reg.mtx);
}
@@ -757,7 +732,7 @@ int reg_create_ipcp(const struct ipcp_info * info)
assert(info != NULL);
assert(info->pid != 0);
- assert(info->state == IPCP_BOOT);
+ assert(info->state == IPCP_INIT);
pthread_mutex_lock(&reg.mtx);
@@ -780,7 +755,7 @@ int reg_create_ipcp(const struct ipcp_info * info)
entry->pid = info->pid;
- list_add(&ipcp->next, __reg_after_ipcp(info->pid));
+ list_add_tail(&ipcp->next, __reg_after_ipcp(info));
list_add(&entry->next, __reg_after_spawned(info->pid));
reg.n_ipcps++;
@@ -848,11 +823,11 @@ static int __get_ipcp_info(ipcp_list_msg_t ** msg,
(*msg)->name = strdup(ipcp->info.name);
if ((*msg)->name == NULL)
- goto fail_name;
+ goto fail_msg;
(*msg)->layer = strdup(ipcp->layer.name);
if ((*msg)->layer == NULL)
- goto fail_layer;
+ goto fail_msg;
(*msg)->pid = ipcp->info.pid;
(*msg)->type = ipcp->info.type;
@@ -860,10 +835,8 @@ static int __get_ipcp_info(ipcp_list_msg_t ** msg,
return 0;
- fail_layer:
- free((*msg)->name);
- fail_name:
- free(*msg);
+ fail_msg:
+ ipcp_list_msg__free_unpacked(*msg, NULL);
*msg = NULL;
fail:
return -1;
@@ -876,10 +849,8 @@ int reg_list_ipcps(ipcp_list_msg_t *** ipcps)
pthread_mutex_lock(&reg.mtx);
- if (reg.n_ipcps == 0) {
- *ipcps = NULL;
+ if (reg.n_ipcps == 0)
goto finish;
- }
*ipcps = malloc(reg.n_ipcps * sizeof(**ipcps));
if (*ipcps == NULL) {
@@ -890,24 +861,19 @@ int reg_list_ipcps(ipcp_list_msg_t *** ipcps)
list_for_each(p, &reg.ipcps) {
struct reg_ipcp * entry;
entry = list_entry(p, struct reg_ipcp, next);
- if (__get_ipcp_info(&((*ipcps)[i]), entry) < 0) {
- log_err("Failed to create ipcp list info.");
+ if (__get_ipcp_info(&(*ipcps)[i], entry) < 0)
goto fail;
- }
- ++i;
+ i++;
}
-
- assert(i == (int) reg.n_ipcps);
finish:
pthread_mutex_unlock(&reg.mtx);
return i;
fail:
- while (i > 0)
- ipcp_list_msg__free_unpacked((*ipcps)[--i], NULL);
-
+ while (i-- > 0)
+ ipcp_list_msg__free_unpacked((*ipcps)[i], NULL);
free(*ipcps);
fail_malloc:
pthread_mutex_unlock(&reg.mtx);
@@ -993,28 +959,84 @@ bool reg_has_name(const char * name)
return ret;
}
-static int __get_name_info(name_info_msg_t ** msg,
- struct reg_name * n)
+int reg_get_name_info(const char * name,
+ struct name_info * info)
{
- *msg = malloc(sizeof(**msg));
- if (*msg == NULL)
- goto fail;
+ struct reg_name * n;
- name_info_msg__init(*msg);
+ assert(name != NULL);
+ assert(info != NULL);
- (*msg)->name = strdup(n->info.name);
- if ((*msg)->name == NULL)
- goto fail_name;
+ pthread_mutex_lock(&reg.mtx);
+
+ n = __reg_get_name(name);
+ if (n == NULL) {
+ log_err("Name %s does not exist.", name);
+ goto no_name;
+ }
- (*msg)->pol_lb = n->info.pol_lb;
+ *info = n->info;
+
+ pthread_mutex_unlock(&reg.mtx);
return 0;
- fail_name:
- free(*msg);
- *msg = NULL;
- fail:
- return -1;
+ no_name:
+ pthread_mutex_unlock(&reg.mtx);
+ return -ENOENT;
+
+}
+
+int reg_get_name_for_hash(char * buf,
+ enum hash_algo algo,
+ const uint8_t * hash)
+{
+ struct list_head * p;
+ uint8_t * thash;
+ size_t len;
+ char * name = NULL;
+
+ len = hash_len(algo);
+
+ thash = malloc(len);
+ if (thash == NULL)
+ return -ENOMEM;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ list_for_each(p, &reg.names) {
+ struct reg_name * n = list_entry(p, struct reg_name, next);
+ str_hash(algo, thash, n->info.name);
+ if (memcmp(thash, hash, len) == 0) {
+ name = n->info.name;
+ break;
+ }
+ }
+
+ if (name != NULL)
+ strcpy(buf, name);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ free(thash);
+
+ return name == NULL ? -ENOENT : 0;
+}
+
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id)
+{
+ struct reg_flow * f;
+
+ pthread_mutex_lock(&reg.mtx);
+
+ f = __reg_get_flow(flow_id);
+ if (f != NULL)
+ strcpy(buf, f->name);
+
+ pthread_mutex_unlock(&reg.mtx);
+
+ return f == NULL ? -ENOENT : 0;
}
int reg_list_names(name_info_msg_t *** names)
@@ -1036,24 +1058,31 @@ int reg_list_names(name_info_msg_t *** names)
list_for_each(p, &reg.names) {
struct reg_name * entry;
entry = list_entry(p, struct reg_name, next);
- if (__get_name_info(&((*names)[i]), entry) < 0) {
+ (*names)[i] = name_info_s_to_msg(&entry->info);
+ if ((*names)[i] == NULL) {
log_err("Failed to create name list info.");
goto fail;
}
-
- ++i;
+ /* wipe security info to avoid huge messages */
+ free((*names)[i]->scrt);
+ (*names)[i]->scrt = NULL;
+ free((*names)[i]->skey);
+ (*names)[i]->skey = NULL;
+ free((*names)[i]->ccrt);
+ (*names)[i]->ccrt = NULL;
+ free((*names)[i]->ckey);
+ (*names)[i]->ckey = NULL;
+
+ i++;
}
-
- assert(i == (int) reg.n_names);
finish:
pthread_mutex_unlock(&reg.mtx);
return i;
fail:
- while (i > 0)
- name_info_msg__free_unpacked((*names)[--i], NULL);
-
+ while (i-- > 0)
+ name_info_msg__free_unpacked((*names)[i], NULL);
free(*names);
fail_malloc:
pthread_mutex_unlock(&reg.mtx);
@@ -1419,19 +1448,18 @@ bool reg_has_prog(const char * name)
return ret;
}
-int reg_get_exec(enum hash_algo algo,
- const uint8_t * hash,
- char *** prog)
+int reg_get_exec(const char * name,
+ char *** prog)
{
char ** exec;
int ret = 0;
- assert(hash != NULL);
+ assert(name != NULL);
assert(prog != NULL);
pthread_mutex_lock(&reg.mtx);
- exec = __reg_get_exec(algo, hash);
+ exec = __reg_get_exec(name);
if (exec == NULL) {
ret = -EPERM;
goto finish;
@@ -1444,12 +1472,9 @@ int reg_get_exec(enum hash_algo algo,
goto finish;
}
- pthread_mutex_unlock(&reg.mtx);
-
- return 0;
-
finish:
pthread_mutex_unlock(&reg.mtx);
+
return ret;
}
@@ -1557,8 +1582,7 @@ int reg_set_layer_for_ipcp(struct ipcp_info * info,
struct reg_ipcp * ipcp;
assert(info != NULL);
- assert(info->state > IPCP_BOOT);
- assert(info->state < IPCP_SHUTDOWN);
+ assert(info->state == IPCP_BOOT);
pthread_mutex_lock(&reg.mtx);
@@ -1690,7 +1714,7 @@ int reg_wait_flow_allocated(struct flow_info * info,
stop = true;
break;
case FLOW_DEALLOCATED:
- ret = -1;
+ ret = flow->response;
stop = true;
break;
default:
@@ -1722,7 +1746,8 @@ int reg_wait_flow_allocated(struct flow_info * info,
}
int reg_respond_alloc(struct flow_info * info,
- buffer_t * pbuf)
+ buffer_t * pbuf,
+ int response)
{
struct reg_flow * flow;
@@ -1755,7 +1780,9 @@ int reg_respond_alloc(struct flow_info * info,
if (reg_flow_update(flow, info) < 0) {
log_err("Failed to create flow structs.");
goto fail_flow;
- };
+ }
+
+ flow->response = response;
if (info->state == FLOW_ALLOCATED)
reg_flow_set_data(flow, pbuf);
@@ -1771,8 +1798,7 @@ int reg_respond_alloc(struct flow_info * info,
return -1;
}
-int reg_prepare_flow_accept(struct flow_info * info,
- buffer_t * pbuf)
+int reg_prepare_flow_accept(struct flow_info * info)
{
struct reg_flow * flow;
int ret;
@@ -1790,8 +1816,6 @@ int reg_prepare_flow_accept(struct flow_info * info,
ret = reg_flow_update(flow, info);
- reg_flow_set_data(flow, pbuf);
-
pthread_mutex_unlock(&reg.mtx);
return ret;
@@ -1824,8 +1848,6 @@ int reg_wait_flow_accepted(struct flow_info * info,
assert(flow != NULL);
assert(info->id == flow->info.id);
assert(info->n_pid == flow->info.n_pid);
- assert(info->state == flow->info.state);
- assert(flow->info.state == FLOW_ACCEPT_PENDING);
if (__reg_add_active_proc(info->n_pid) < 0) {
log_err("Failed to mark pid %d active.", info->n_pid);
@@ -1883,13 +1905,12 @@ int reg_wait_flow_accepted(struct flow_info * info,
return -1;
}
-int reg_wait_flow_accepting(enum hash_algo algo,
- const uint8_t * hash,
+int reg_wait_flow_accepting(const char * name,
const struct timespec * abstime)
{
int ret;
- assert(hash != NULL);
+ assert(name != NULL);
assert(abstime != NULL);
pthread_mutex_lock(&reg.mtx);
@@ -1897,7 +1918,7 @@ int reg_wait_flow_accepting(enum hash_algo algo,
pthread_cleanup_push(__cleanup_mutex_unlock, &reg.mtx);
while (true) {
- ret = __reg_get_pending_flow_id_for_hash(algo, hash);
+ ret = __reg_get_pending_flow_id(name);
if (ret != -EAGAIN)
break;
@@ -1915,7 +1936,6 @@ int reg_respond_accept(struct flow_info * info,
buffer_t * pbuf)
{
struct reg_flow * flow;
- buffer_t temp;
assert(info != NULL);
assert(info->state == FLOW_ALLOCATED);
@@ -1933,11 +1953,8 @@ int reg_respond_accept(struct flow_info * info,
info->n_pid = flow->info.n_pid;
- if (info->qs.cypher_s > 0) {
- reg_flow_get_data(flow, &temp);
- reg_flow_set_data(flow, pbuf);
- *pbuf = temp;
- }
+ reg_flow_set_data(flow, pbuf);
+ clrbuf(pbuf);
if (reg_flow_update(flow, info) < 0) {
log_err("Failed to create flow structs.");
@@ -1970,12 +1987,14 @@ void reg_dealloc_flow(struct flow_info * info)
assert(flow != NULL);
assert(flow->data.data == NULL);
assert(flow->data.len == 0);
-
assert(flow->info.state == FLOW_ALLOCATED);
+
flow->info.state = FLOW_DEALLOC_PENDING;
info->state = FLOW_DEALLOC_PENDING;
info->n_1_pid = flow->info.n_1_pid;
+ memset(flow->name, 0, sizeof(flow->name));
+
reg_flow_update(flow, info);
pthread_mutex_unlock(&reg.mtx);
@@ -2043,7 +2062,7 @@ int reg_wait_ipcp_boot(struct ipcp_info * info,
int ret;
bool stop = false;
- assert(info->state == IPCP_BOOT);
+ assert(info->state == IPCP_INIT);
pthread_mutex_lock(&reg.mtx);
@@ -2063,16 +2082,18 @@ int reg_wait_ipcp_boot(struct ipcp_info * info,
ret = -1;
stop = true;
break;
+ case IPCP_BOOT:
+ /* FALLTHRU*/
case IPCP_OPERATIONAL:
ret = 0;
stop = true;
break;
- case IPCP_BOOT:
+ case IPCP_INIT:
ret = -__timedwait(&reg.cond, &reg.mtx, abstime);
break;
default:
assert(false);
- continue; /* Shut up static analyzer. */
+ break; /* Shut up static analyzer. */
}
ipcp = __reg_get_ipcp(info->pid);
diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h
index 17dfcc32..7728c80f 100644
--- a/src/irmd/reg/reg.h
+++ b/src/irmd/reg/reg.h
@@ -90,6 +90,16 @@ int reg_destroy_name(const char * name);
bool reg_has_name(const char * name);
+int reg_get_name_info(const char * name,
+ struct name_info * info);
+
+int reg_get_name_for_hash(char * buf,
+ enum hash_algo algo,
+ const uint8_t * hash);
+
+int reg_get_name_for_flow_id(char * buf,
+ int flow_id);
+
/* TODO don't rely on protobuf here */
int reg_list_names(name_info_msg_t *** names);
@@ -99,9 +109,8 @@ int reg_destroy_prog(const char * name);
bool reg_has_prog(const char * name);
-int reg_get_exec(enum hash_algo algo,
- const uint8_t * hash,
- char *** exec);
+int reg_get_exec(const char * name,
+ char *** exec);
int reg_bind_prog(const char * name,
char ** exec,
@@ -117,17 +126,16 @@ int reg_wait_flow_allocated(struct flow_info * info,
const struct timespec * abstime);
int reg_respond_alloc(struct flow_info * info,
- buffer_t * pbuf);
+ buffer_t * pbuf,
+ int response);
-int reg_prepare_flow_accept(struct flow_info * info,
- buffer_t * pbuf);
+int reg_prepare_flow_accept(struct flow_info * info);
int reg_wait_flow_accepted(struct flow_info * info,
buffer_t * pbuf,
const struct timespec * abstime);
-int reg_wait_flow_accepting(enum hash_algo algo,
- const uint8_t * hash,
+int reg_wait_flow_accepting(const char * name,
const struct timespec * abstime);
int reg_respond_accept(struct flow_info * info,
diff --git a/src/irmd/reg/tests/CMakeLists.txt b/src/irmd/reg/tests/CMakeLists.txt
index bc1354ed..7bc98571 100644
--- a/src/irmd/reg/tests/CMakeLists.txt
+++ b/src/irmd/reg/tests/CMakeLists.txt
@@ -21,7 +21,11 @@ endif ()
add_dependencies(check ${src_folder}_test)
set(tests_to_run ${${src_folder}_tests})
-remove(tests_to_run test_suite.c)
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
foreach(test ${tests_to_run})
get_filename_component(test_name ${test} NAME_WE)
diff --git a/src/irmd/reg/tests/flow_test.c b/src/irmd/reg/tests/flow_test.c
index f9d23fd1..27fd61b0 100644
--- a/src/irmd/reg/tests/flow_test.c
+++ b/src/irmd/reg/tests/flow_test.c
@@ -28,7 +28,7 @@
#define TEST_DATA "testpiggybackdata"
-static int test_reg_flow_create(void)
+static int test_reg_flow_create_destroy(void)
{
struct reg_flow * f;
@@ -51,10 +51,10 @@ static int test_reg_flow_create(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow_create_no_id(void) {
@@ -67,7 +67,7 @@ static int test_reg_flow_create_no_id(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_no_pid(void) {
@@ -80,7 +80,7 @@ static int test_reg_flow_create_no_pid(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_has_n_1_pid(void) {
@@ -94,7 +94,7 @@ static int test_reg_flow_create_has_n_1_pid(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_wrong_state(void) {
@@ -108,7 +108,7 @@ static int test_reg_flow_create_wrong_state(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_create_has_mpl(void) {
@@ -123,7 +123,7 @@ static int test_reg_flow_create_has_mpl(void) {
reg_flow_create(&info); /* assert fail */
- return 0;
+ return TEST_RC_SUCCESS;
}
static int test_reg_flow_update(void)
@@ -163,10 +163,10 @@ static int test_reg_flow_update(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow_update_wrong_id(void)
@@ -199,10 +199,10 @@ static int test_reg_flow_update_wrong_id(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow_assert_fails(void)
@@ -210,15 +210,10 @@ static int test_reg_flow_assert_fails(void)
int ret = 0;
ret |= test_assert_fail(test_reg_flow_create_no_id);
-
ret |= test_assert_fail(test_reg_flow_create_no_pid);
-
ret |= test_assert_fail(test_reg_flow_create_has_n_1_pid);
-
ret |= test_assert_fail(test_reg_flow_create_wrong_state);
-
ret |= test_assert_fail(test_reg_flow_create_has_mpl);
-
ret |= test_assert_fail(test_reg_flow_update_wrong_id);
return ret;
@@ -237,7 +232,7 @@ static int test_flow_data(void)
char * data;
buffer_t buf;
- buffer_t rcv = {NULL, 0};
+ buffer_t rcv = {0, NULL};
TEST_START();
@@ -267,11 +262,11 @@ static int test_flow_data(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
free(data);
TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
int flow_test(int argc,
@@ -282,12 +277,9 @@ int flow_test(int argc,
(void) argc;
(void) argv;
- ret |= test_reg_flow_create();
-
+ ret |= test_reg_flow_create_destroy();
ret |= test_reg_flow_update();
-
ret |= test_reg_flow_assert_fails();
-
ret |= test_flow_data();
return ret;
diff --git a/src/irmd/reg/tests/ipcp_test.c b/src/irmd/reg/tests/ipcp_test.c
index fb8ba71b..d7d8e524 100644
--- a/src/irmd/reg/tests/ipcp_test.c
+++ b/src/irmd/reg/tests/ipcp_test.c
@@ -31,7 +31,7 @@ static int test_reg_ipcp_create(void)
struct reg_ipcp * ipcp;
struct ipcp_info info = {
.pid = TEST_PID,
- .state = IPCP_BOOT
+ .state = IPCP_INIT
};
struct layer_info layer = {
.name = "testlayer",
@@ -51,7 +51,7 @@ static int test_reg_ipcp_create(void)
goto fail;
}
- ipcp->info.state = IPCP_OPERATIONAL;
+ ipcp->info.state = IPCP_BOOT;
reg_ipcp_set_layer(ipcp, &layer);
@@ -60,11 +60,6 @@ static int test_reg_ipcp_create(void)
goto fail;
}
- if (ipcp->info.state != IPCP_OPERATIONAL) {
- printf("IPCP state was not set.\n");
- goto fail;
- }
-
reg_ipcp_destroy(ipcp);
TEST_SUCCESS();
diff --git a/src/irmd/reg/tests/name_test.c b/src/irmd/reg/tests/name_test.c
index 48f132e9..9071364b 100644
--- a/src/irmd/reg/tests/name_test.c
+++ b/src/irmd/reg/tests/name_test.c
@@ -20,8 +20,11 @@
* Foundation, Inc., http://www.fsf.org/about/contact/.
*/
+
#include "../name.c"
+#include <ouroboros/test.h>
+
#define TEST_PID 65534
#define TEST_PROG "/usr/bin/testprog"
#define TEST_NAME "testservicename"
@@ -34,6 +37,8 @@ static int test_reg_name_create(void)
.pol_lb = LB_RR,
};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -42,9 +47,12 @@ static int test_reg_name_create(void)
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name_add_proc(void)
@@ -55,6 +63,8 @@ static int test_reg_name_add_proc(void)
.pol_lb = LB_RR,
};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -66,8 +76,8 @@ static int test_reg_name_add_proc(void)
goto fail;
}
- if (n->n_procs != 1) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 1) {
+ printf("Proc not added to list.\n");
goto fail;
}
@@ -78,16 +88,19 @@ static int test_reg_name_add_proc(void)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Proc not removed from list.\n");
goto fail;
}
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name_add_prog(void)
@@ -100,6 +113,8 @@ static int test_reg_name_add_prog(void)
char * exec[] = { TEST_PROG, "--argswitch", "argvalue", NULL};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -111,8 +126,8 @@ static int test_reg_name_add_prog(void)
goto fail;
}
- if (n->n_progs != 1) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 1) {
+ printf("Prog not added to list.\n");
goto fail;
}
@@ -123,16 +138,19 @@ static int test_reg_name_add_prog(void)
reg_name_del_prog(n, TEST_PROG);
- if (n->n_progs != 0) {
- printf("n_progs not updated.\n");
+ if (n->progs.len != 0) {
+ printf("Prog not removed from list.\n");
goto fail;
}
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name_add_active(enum pol_balance lb)
@@ -144,6 +162,8 @@ static int test_reg_name_add_active(enum pol_balance lb)
.pol_lb = lb,
};
+ TEST_START();
+
n = reg_name_create(&info);
if (n == NULL) {
printf("Failed to create name %s.\n", info.name);
@@ -175,8 +195,8 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_active != 1) {
- printf("n_active not updated.\n");
+ if (n->active.len != 1) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -206,13 +226,13 @@ static int test_reg_name_add_active(enum pol_balance lb)
goto fail;
}
- if (n->n_procs != 3) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 3) {
+ printf("Procs list not updated.\n");
goto fail;
}
- if (n->n_active != 4) {
- printf("n_active not updated.\n");
+ if (n->active.len != 4) {
+ printf("Active list not updated.\n");
goto fail;
}
@@ -243,41 +263,39 @@ static int test_reg_name_add_active(enum pol_balance lb)
reg_name_del_proc(n, TEST_PID);
- if (n->n_procs != 0) {
- printf("n_procs not updated.\n");
+ if (n->procs.len != 0) {
+ printf("Procs list not cleared.\n");
goto fail;
}
- if (n->n_active != 0) {
- printf("n_active not updated.\n");
+ if (n->active.len != 0) {
+ printf("Active list not cleared.\n");
goto fail;
}
reg_name_destroy(n);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
-
int name_test(int argc,
char ** argv)
{
- int res = 0;
+ int rc = 0;
(void) argc;
(void) argv;
- res |= test_reg_name_create();
-
- res |= test_reg_name_add_proc();
-
- res |= test_reg_name_add_prog();
-
- res |= test_reg_name_add_active(LB_RR);
-
- res |= test_reg_name_add_active(LB_SPILL);
+ rc |= test_reg_name_create();
+ rc |= test_reg_name_add_proc();
+ rc |= test_reg_name_add_prog();
+ rc |= test_reg_name_add_active(LB_RR);
+ rc |= test_reg_name_add_active(LB_SPILL);
- return res;
+ return rc;
}
diff --git a/src/irmd/reg/tests/proc_test.c b/src/irmd/reg/tests/proc_test.c
index 5c9dd865..df0527fb 100644
--- a/src/irmd/reg/tests/proc_test.c
+++ b/src/irmd/reg/tests/proc_test.c
@@ -22,10 +22,12 @@
#include "../proc.c"
+#include <ouroboros/test.h>
+
#define TEST_PID 65534
#define TEST_PROG "usr/bin/testprog"
-static int test_reg_proc_create(void)
+static int test_reg_proc_create_destroy(void)
{
struct reg_proc * proc;
struct proc_info info = {
@@ -33,6 +35,8 @@ static int test_reg_proc_create(void)
.prog = TEST_PROG
};
+ TEST_START();
+
proc = reg_proc_create(&info);
if (proc == NULL) {
printf("Failed to create proc.\n");
@@ -41,9 +45,12 @@ static int test_reg_proc_create(void)
reg_proc_destroy(proc);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_proc_add_name(void)
@@ -56,6 +63,8 @@ static int test_reg_proc_add_name(void)
char * name = "testname";
+ TEST_START();
+
proc = reg_proc_create(&info);
if (proc == NULL) {
printf("Failed to create proc.\n");
@@ -86,9 +95,12 @@ static int test_reg_proc_add_name(void)
reg_proc_destroy(proc);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
int proc_test(int argc,
@@ -99,8 +111,7 @@ int proc_test(int argc,
(void) argc;
(void) argv;
- res |= test_reg_proc_create();
-
+ res |= test_reg_proc_create_destroy();
res |= test_reg_proc_add_name();
return res;
diff --git a/src/irmd/reg/tests/prog_test.c b/src/irmd/reg/tests/prog_test.c
index 5e6931d8..c394c222 100644
--- a/src/irmd/reg/tests/prog_test.c
+++ b/src/irmd/reg/tests/prog_test.c
@@ -22,8 +22,9 @@
#include "../prog.c"
-#define TEST_PROG "usr/bin/testprog"
+#include <ouroboros/test.h>
+#define TEST_PROG "usr/bin/testprog"
static int test_reg_prog_create(void)
{
@@ -32,6 +33,8 @@ static int test_reg_prog_create(void)
.name = TEST_PROG
};
+ TEST_START();
+
prog = reg_prog_create(&info);
if (prog == NULL) {
printf("Failed to create prog.\n");
@@ -40,9 +43,12 @@ static int test_reg_prog_create(void)
reg_prog_destroy(prog);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_prog_add_name(void)
@@ -54,6 +60,8 @@ static int test_reg_prog_add_name(void)
char * name = "testname";
+ TEST_START();
+
prog = reg_prog_create(&info);
if (prog == NULL) {
printf("Failed to create prog.\n");
@@ -84,9 +92,12 @@ static int test_reg_prog_add_name(void)
reg_prog_destroy(prog);
- return 0;
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
fail:
- return -1;
+ TEST_FAIL();
+ return TEST_RC_FAIL;
}
int prog_test(int argc,
@@ -98,7 +109,6 @@ int prog_test(int argc,
(void) argv;
ret |= test_reg_prog_create();
-
ret |= test_reg_prog_add_name();
return ret;
diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c
index c341c297..4699beab 100644
--- a/src/irmd/reg/tests/reg_test.c
+++ b/src/irmd/reg/tests/reg_test.c
@@ -36,7 +36,7 @@
#define TEST_DATA2 "testpbufdata2"
#define TEST_LAYER "testlayer"
#define REG_TEST_FAIL() \
- do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); } while(0)
+ do { TEST_FAIL(); memset(&reg, 0, sizeof(reg)); abort();} while(0)
static int test_reg_init(void)
{
@@ -51,10 +51,10 @@ static int test_reg_init(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_create_flow(void)
@@ -105,18 +105,17 @@ static int test_reg_create_flow(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_allocate_flow_timeout(void)
{
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_MS(1);
- buffer_t pbuf;
- buffer_t rbuf = {NULL, 0};
+ buffer_t rbuf = BUF_INIT;
struct flow_info info = {
.n_pid = TEST_PID,
@@ -125,14 +124,6 @@ static int test_reg_allocate_flow_timeout(void)
TEST_START();
- pbuf.data = (uint8_t *) strdup(TEST_DATA);;
- if (pbuf.data == NULL) {
- printf("Failed to strdup data.\n");
- goto fail;
- }
-
- pbuf.len = strlen((char *) pbuf.data) + 1;
-
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
@@ -147,7 +138,7 @@ static int test_reg_allocate_flow_timeout(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -162,12 +153,6 @@ static int test_reg_allocate_flow_timeout(void)
goto fail;
}
- if (pbuf.data == NULL) {
- printf("Flow data was updated on timeout.");
- goto fail;
- }
-
- freebuf(pbuf);
reg_destroy_flow(info.id);
if (reg.n_flows != 0) {
@@ -179,16 +164,19 @@ static int test_reg_allocate_flow_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_flow_respond_alloc(void * o)
{
struct flow_info * info = (struct flow_info *) o;
- buffer_t pbuf = {NULL, 0};
+ buffer_t pbuf = BUF_INIT;
+ int response;
+
+ response = (info->state == FLOW_ALLOCATED) ? 0 : -1;
if (info->state == FLOW_ALLOCATED) {
pbuf.data = (uint8_t *) strdup(TEST_DATA2);
@@ -199,7 +187,7 @@ static void * test_flow_respond_alloc(void * o)
pbuf.len = strlen((char *) pbuf.data) + 1;
}
- reg_respond_alloc(info, &pbuf);
+ reg_respond_alloc(info, &pbuf, response);
return (void *) 0;
fail:
@@ -220,13 +208,6 @@ static void * test_flow_respond_accept(void * o)
reg_respond_accept(info, &pbuf);
- if (info->qs.cypher_s == 0) {
- freebuf(pbuf);
- } else if (strcmp((char *) pbuf.data, TEST_DATA) != 0) {
- printf("Data was not passed correctly.\n");
- goto fail;
- }
-
return (void *) 0;
fail:
return (void *) -1;
@@ -237,8 +218,7 @@ static int test_reg_accept_flow_success(void)
pthread_t thr;
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
- buffer_t pbuf = {(uint8_t *) TEST_DATA, strlen(TEST_DATA)};
- buffer_t rbuf = {NULL, 0};
+ buffer_t rbuf = BUF_INIT;
struct flow_info info = {
.n_pid = TEST_PID,
@@ -247,7 +227,7 @@ static int test_reg_accept_flow_success(void)
struct flow_info n_1_info = {
.n_1_pid = TEST_N_1_PID,
- .qs = qos_data_crypt,
+ .qs = qos_data,
.state = FLOW_ALLOCATED /* RESPONSE SUCCESS */
};
@@ -267,7 +247,7 @@ static int test_reg_accept_flow_success(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -277,7 +257,7 @@ static int test_reg_accept_flow_success(void)
pthread_create(&thr, NULL, test_flow_respond_accept, &n_1_info);
- if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0 ) {
+ if (reg_wait_flow_accepted(&info, &rbuf, &abstime) < 0) {
printf("Flow allocation failed.\n");
goto fail;
}
@@ -321,10 +301,10 @@ static int test_reg_accept_flow_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_accept_flow_success_no_crypt(void)
@@ -332,8 +312,7 @@ static int test_reg_accept_flow_success_no_crypt(void)
pthread_t thr;
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
- buffer_t pbuf = {(uint8_t *) TEST_DATA, strlen(TEST_DATA)};
- buffer_t rbuf = {NULL, 0};
+ buffer_t rbuf = BUF_INIT;
struct flow_info info = {
.n_pid = TEST_PID,
@@ -362,7 +341,7 @@ static int test_reg_accept_flow_success_no_crypt(void)
goto fail;
}
- if (reg_prepare_flow_accept(&info, &pbuf) < 0) {
+ if (reg_prepare_flow_accept(&info) < 0) {
printf("Failed to prepare flow for accept.\n");
goto fail;
}
@@ -389,10 +368,7 @@ static int test_reg_accept_flow_success_no_crypt(void)
goto fail;
}
- if (strcmp((char *) rbuf.data, TEST_DATA) != 0) {
- printf("Data was updated.\n");
- goto fail;
- }
+ freebuf(rbuf);
n_1_info.state = FLOW_DEALLOCATED;
@@ -416,16 +392,16 @@ static int test_reg_accept_flow_success_no_crypt(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_allocate_flow_fail(void)
{
- buffer_t buf = {NULL, 0};
+ buffer_t buf = BUF_INIT;
pthread_t thr;
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
@@ -486,26 +462,22 @@ static int test_reg_allocate_flow_fail(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_flow(void) {
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_flow();
+ rc |= test_reg_create_flow();
+ rc |= test_reg_allocate_flow_timeout();
+ rc |= test_reg_accept_flow_success();
+ rc |= test_reg_accept_flow_success_no_crypt();
+ rc |= test_reg_allocate_flow_fail();
- ret |= test_reg_allocate_flow_timeout();
-
- ret |= test_reg_accept_flow_success();
-
- ret |= test_reg_accept_flow_success_no_crypt();
-
- ret |= test_reg_allocate_flow_fail();
-
- return ret;
+ return rc;
}
static int test_reg_create_ipcp(void)
@@ -513,7 +485,7 @@ static int test_reg_create_ipcp(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
TEST_START();
@@ -552,10 +524,130 @@ static int test_reg_create_ipcp(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
+ fail:
+ REG_TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_reg_list_ipcps(void)
+{
+ ipcp_list_msg_t ** ipcps;
+ int i;
+ ssize_t len;
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < 10; i++) {
+ struct ipcp_info info = {
+ .pid = TEST_PID + i,
+ .state = IPCP_INIT /* set by spawn_ipcp */
+ };
+
+ sprintf(info.name, "%s%d", TEST_IPCP, i);
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp %d.\n", i);
+ goto fail;
+ }
+ }
+
+ len = reg_list_ipcps(&ipcps);
+ if (len < 0) {
+ printf("Failed to list ipcps.\n");
+ goto fail;
+ }
+
+ if (len != 10) {
+ printf("Failed to list all ipcps.\n");
+ goto fail;
+ }
+
+ while (len-- > 0)
+ ipcp_list_msg__free_unpacked(ipcps[len], NULL);
+ free(ipcps);
+
+ for (i = 0; i < 10; i++)
+ reg_destroy_proc(TEST_PID + i);
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
+}
+
+static int test_insert_ipcps(void)
+{
+ ipcp_list_msg_t ** ipcps;
+ struct ipcp_info info;
+ size_t i;
+ size_t len;
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < 100; i++) {
+ sprintf(info.name, "%s-%zd", TEST_IPCP, i);
+ info.pid = TEST_PID + rand() % 10000;
+ info.type = rand() % IPCP_INVALID;
+ info.state = IPCP_INIT; /* set by spawn_ipcp */
+
+ if (reg_create_ipcp(&info) < 0) {
+ printf("Failed to create ipcp %s.\n", info.name);
+ goto fail;
+ }
+ }
+
+ len = reg_list_ipcps(&ipcps);
+ if (len != 100) {
+ printf("Failed to list all ipcps.\n");
+ goto fail;
+ }
+
+ for (i = 1; i < len; i++) {
+ if (ipcps[i]->type < ipcps[i - 1]->type) {
+ printf("IPCPS not sorted by type.\n");
+ goto fail;
+ }
+
+ if (ipcps[i]->type != ipcps[i - 1]->type)
+ continue;
+
+ /* allow occasional duplicate PID in test */
+ if (ipcps[i]->pid < ipcps[i - 1]->pid) {
+ printf("IPCPS not sorted by pid.\n");
+ goto fail;
+ }
+ }
+
+ while (len-- > 0)
+ ipcp_list_msg__free_unpacked(ipcps[len], NULL);
+ free(ipcps);
+
+ reg_clear();
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+fail:
+ REG_TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_set_layer(void)
@@ -564,7 +656,7 @@ static int test_set_layer(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
struct layer_info layer = {
.name = TEST_LAYER,
@@ -588,8 +680,9 @@ static int test_set_layer(void)
}
ipcp = __reg_get_ipcp(info.pid);
- ipcp->info.state = IPCP_OPERATIONAL;
- info.state = IPCP_ENROLLED;
+
+ ipcp->info.state = IPCP_BOOT;
+ info.state = IPCP_BOOT;
reg_set_layer_for_ipcp(&info, &layer);
@@ -614,21 +707,22 @@ static int test_set_layer(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_ipcp(void)
{
- int ret = 0;
-
- ret |= test_reg_create_ipcp();
+ int rc = 0;
- ret |= test_set_layer();
+ rc |= test_reg_create_ipcp();
+ rc |= test_reg_list_ipcps();
+ rc |= test_insert_ipcps();
+ rc |= test_set_layer();
- return ret;
+ return rc;
}
static int test_reg_create_name(void)
@@ -674,19 +768,77 @@ static int test_reg_create_name(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
+}
+
+static int test_reg_list_names(void)
+{
+ name_info_msg_t ** names;
+ int i;
+ ssize_t len;
+
+ TEST_START();
+
+ if (reg_init() < 0) {
+ printf("Failed to init registry.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < 10; i++) {
+ struct name_info info = {
+ .pol_lb = LB_RR
+ };
+
+ sprintf(info.name, "%s%d", TEST_NAME, i);
+
+ if (reg_create_name(&info) < 0) {
+ printf("Failed to create name %d.\n", i);
+ goto fail;
+ }
+ }
+
+ len = reg_list_names(&names);
+ if (len < 0) {
+ printf("Failed to list names.\n");
+ goto fail;
+ }
+
+ if (len != 10) {
+ printf("Failed to list all names.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < len; i++)
+ name_info_msg__free_unpacked(names[i], NULL);
+ free(names);
+
+ for (i = 0; i < 10; i++) {
+ char name[NAME_MAX];
+ sprintf(name, "%s%d", TEST_NAME, i);
+ reg_destroy_name(name);
+ }
+
+ reg_fini();
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+ fail:
+ REG_TEST_FAIL();
+ return TEST_RC_FAIL;
}
static int test_reg_name(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_name();
+ rc |= test_reg_create_name();
+ rc |= test_reg_list_names();
- return ret;
+ return rc;
}
static int test_reg_create_proc(void)
@@ -732,19 +884,19 @@ static int test_reg_create_proc(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_proc(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_proc();
+ rc |= test_reg_create_proc();
- return ret;
+ return rc;
}
static int test_reg_spawned(void)
@@ -785,10 +937,10 @@ static int test_reg_spawned(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_create_prog(void)
@@ -833,19 +985,19 @@ static int test_reg_create_prog(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_reg_prog(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_reg_create_prog();
+ rc |= test_reg_create_prog();
- return ret;
+ return rc;
}
static int test_bind_proc(void)
@@ -900,10 +1052,10 @@ static int test_bind_proc(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_bind_prog(void)
@@ -989,10 +1141,10 @@ static int test_bind_prog(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_inherit_prog(void)
@@ -1060,10 +1212,10 @@ static int test_inherit_prog(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_accepting_timeout(void)
@@ -1071,7 +1223,6 @@ static int test_wait_accepting_timeout(void)
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_MS(1);
int flow_id;
- uint8_t hash[64];
struct name_info ninfo = {
.name = TEST_NAME,
.pol_lb = LB_RR
@@ -1089,12 +1240,10 @@ static int test_wait_accepting_timeout(void)
goto fail;
}
- str_hash(HASH_SHA3_256, hash, ninfo.name);
-
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- flow_id = reg_wait_flow_accepting(HASH_SHA3_256, hash, &abstime);
+ flow_id = reg_wait_flow_accepting(ninfo.name, &abstime);
if (flow_id != -ETIMEDOUT) {
printf("Wait accept did not time out: %d.\n", flow_id);
goto fail;
@@ -1106,10 +1255,10 @@ static int test_wait_accepting_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_accepting_fail_name(void)
@@ -1117,7 +1266,6 @@ static int test_wait_accepting_fail_name(void)
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
int flow_id;
- uint8_t hash[64];
TEST_START();
@@ -1128,11 +1276,10 @@ static int test_wait_accepting_fail_name(void)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- str_hash(HASH_SHA3_256, hash, "C0FF33");
- flow_id = reg_wait_flow_accepting(HASH_SHA3_256, hash, &abstime);
+ flow_id = reg_wait_flow_accepting(TEST_NAME, &abstime);
if (flow_id != -ENAME) {
- printf("Wait accept did not fail on name: %d.\n", flow_id);
+ printf("Wait accept did not fail: %d.\n", flow_id);
goto fail;
}
@@ -1140,17 +1287,17 @@ static int test_wait_accepting_fail_name(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_call_flow_accept(void * o)
{
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_MS(1);
- buffer_t pbuf = {NULL, 0};
+ buffer_t pbuf = BUF_INIT;
struct proc_info pinfo = {
.pid = TEST_PID,
@@ -1182,7 +1329,7 @@ static void * test_call_flow_accept(void * o)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- reg_prepare_flow_accept(&info, &pbuf);
+ reg_prepare_flow_accept(&info);
if (reg_wait_flow_accepted(&info, &pbuf, &abstime) != -ETIMEDOUT) {
printf("Wait allocated did not timeout.\n");
@@ -1201,14 +1348,14 @@ static int test_wait_accepting_success(void)
{
struct timespec abstime;
struct timespec timeo = TIMESPEC_INIT_S(1);
- int flow_id;
pthread_t thr;
- uint8_t hash[64];
+ int flow_id;
struct name_info ninfo = {
.name = TEST_NAME,
.pol_lb = LB_RR
};
+
TEST_START();
if (reg_init()) {
@@ -1226,9 +1373,7 @@ static int test_wait_accepting_success(void)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- str_hash(HASH_SHA3_256, hash, ninfo.name);
-
- flow_id = reg_wait_flow_accepting(HASH_SHA3_256, hash, &abstime);
+ flow_id = reg_wait_flow_accepting(ninfo.name, &abstime);
if (flow_id < 0) {
printf("Wait accept did not return a flow id: %d.", flow_id);
goto fail;
@@ -1242,23 +1387,21 @@ static int test_wait_accepting_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_accepting(void)
{
- int ret = 0;
-
- ret |= test_wait_accepting_timeout();
+ int rc = 0;
- ret |= test_wait_accepting_fail_name();
+ rc |= test_wait_accepting_timeout();
+ rc |= test_wait_accepting_fail_name();
+ rc |= test_wait_accepting_success();
- ret |= test_wait_accepting_success();
-
- return ret;
+ return rc;
}
static int test_wait_ipcp_boot_timeout(void)
@@ -1268,7 +1411,7 @@ static int test_wait_ipcp_boot_timeout(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
TEST_START();
@@ -1300,10 +1443,10 @@ static int test_wait_ipcp_boot_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_ipcp_respond(void * o)
@@ -1323,12 +1466,12 @@ static int test_wait_ipcp_boot_fail(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
struct ipcp_info resp_info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_NULL
+ .state = IPCP_INIT
};
TEST_START();
@@ -1348,7 +1491,7 @@ static int test_wait_ipcp_boot_fail(void)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- info.state = IPCP_BOOT;
+ info.state = IPCP_INIT;
if (reg_wait_ipcp_boot(&info, &abstime) == 0) {
printf("IPCP boot reported success.\n");
@@ -1371,10 +1514,10 @@ static int test_wait_ipcp_boot_fail(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_ipcp_boot_success(void)
@@ -1385,7 +1528,7 @@ static int test_wait_ipcp_boot_success(void)
struct ipcp_info info = {
.name = TEST_IPCP,
.pid = TEST_PID,
- .state = IPCP_BOOT /* set by spawn_ipcp */
+ .state = IPCP_INIT /* set by spawn_ipcp */
};
struct ipcp_info resp_info = {
.name = TEST_IPCP,
@@ -1410,7 +1553,7 @@ static int test_wait_ipcp_boot_success(void)
clock_gettime(PTHREAD_COND_CLOCK, &abstime);
ts_add(&abstime, &timeo, &abstime);
- info.state = IPCP_BOOT;
+ info.state = IPCP_INIT;
if (reg_wait_ipcp_boot(&info, &abstime) < 0) {
printf("IPCP boot failed.\n");
@@ -1433,23 +1576,21 @@ static int test_wait_ipcp_boot_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_ipcp_boot(void)
{
- int ret = 0;
-
- ret |= test_wait_ipcp_boot_timeout();
-
- ret |= test_wait_ipcp_boot_fail();
+ int rc = 0;
- ret |= test_wait_ipcp_boot_success();
+ rc |= test_wait_ipcp_boot_timeout();
+ rc |= test_wait_ipcp_boot_fail();
+ rc |= test_wait_ipcp_boot_success();
- return ret;
+ return rc;
}
static int test_wait_proc_timeout(void)
@@ -1477,10 +1618,10 @@ static int test_wait_proc_timeout(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static void * test_proc(void * o)
@@ -1527,57 +1668,43 @@ static int test_wait_proc_success(void)
TEST_SUCCESS();
- return 0;
+ return TEST_RC_SUCCESS;
fail:
REG_TEST_FAIL();
- return -1;
+ return TEST_RC_FAIL;
}
static int test_wait_proc(void)
{
- int ret = 0;
+ int rc = 0;
- ret |= test_wait_proc_timeout();
+ rc |= test_wait_proc_timeout();
+ rc |= test_wait_proc_success();
- ret |= test_wait_proc_success();
-
- return ret;
+ return rc;
}
-
int reg_test(int argc,
char ** argv)
{
- int ret = 0;
+ int rc = 0;
(void) argc;
(void) argv;
- ret |= test_reg_init();
-
- ret |= test_reg_flow();
-
- ret |= test_reg_ipcp();
-
- ret |= test_reg_name();
-
- ret |= test_reg_proc();
-
- ret |= test_reg_prog();
-
- ret |= test_reg_spawned();
-
- ret |= test_bind_proc();
-
- ret |= test_bind_prog();
-
- ret |= test_inherit_prog();
-
- ret |= test_wait_accepting();
-
- ret |= test_wait_ipcp_boot();
-
- ret |= test_wait_proc();
-
- return ret;
+ rc |= test_reg_init();
+ rc |= test_reg_flow();
+ rc |= test_reg_ipcp();
+ rc |= test_reg_name();
+ rc |= test_reg_proc();
+ rc |= test_reg_prog();
+ rc |= test_reg_spawned();
+ rc |= test_bind_proc();
+ rc |= test_bind_prog();
+ rc |= test_inherit_prog();
+ rc |= test_wait_accepting();
+ rc |= test_wait_ipcp_boot();
+ rc |= test_wait_proc();
+
+ return rc;
}
diff --git a/src/irmd/tests/CMakeLists.txt b/src/irmd/tests/CMakeLists.txt
index e005d194..e860acce 100644
--- a/src/irmd/tests/CMakeLists.txt
+++ b/src/irmd/tests/CMakeLists.txt
@@ -3,6 +3,8 @@ get_filename_component(src_folder "${tmp}" NAME)
create_test_sourcelist(${src_folder}_tests test_suite.c
# Add new tests here
+ irm_test.c
+ oap_test.c
)
add_executable(${src_folder}_test EXCLUDE_FROM_ALL ${${src_folder}_tests})
@@ -11,9 +13,15 @@ target_link_libraries(${src_folder}_test ouroboros-common)
add_dependencies(check ${src_folder}_test)
set(tests_to_run ${${src_folder}_tests})
-remove(tests_to_run test_suite.c)
+if(CMAKE_VERSION VERSION_LESS "3.29.0")
+ remove(tests_to_run test_suite.c)
+else ()
+ list(POP_FRONT tests_to_run)
+endif()
foreach(test ${tests_to_run})
get_filename_component(test_name ${test} NAME_WE)
add_test(irmd/${test_name} ${C_TEST_PATH}/${src_folder}_test ${test_name})
endforeach(test)
+
+set_property(TEST irmd/oap_test PROPERTY SKIP_RETURN_CODE 1)
diff --git a/src/irmd/tests/irm_test.c b/src/irmd/tests/irm_test.c
new file mode 100644
index 00000000..d440289c
--- /dev/null
+++ b/src/irmd/tests/irm_test.c
@@ -0,0 +1,33 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Unit tests of IRMd functions
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+
+
+int irm_test(int argc,
+ char **argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ return ret;
+}
diff --git a/src/irmd/tests/oap_test.c b/src/irmd/tests/oap_test.c
new file mode 100644
index 00000000..4e7fb2d1
--- /dev/null
+++ b/src/irmd/tests/oap_test.c
@@ -0,0 +1,285 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2024
+ *
+ * Unit tests of Ouroboros flow allocation protocol
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., http://www.fsf.org/about/contact/.
+ */
+
+#include "config.h"
+
+#include "oap.c"
+
+#include <ouroboros/random.h>
+#include <ouroboros/test.h>
+
+static const char * pkp_str = \
+"-----BEGIN EC PRIVATE KEY-----\n"
+"MHcCAQEEIC13y+5jdKe80HBJD7WITpQamcn3rrkTX1r0v+JwSk4NoAoGCCqGSM49\n"
+"AwEHoUQDQgAEcC0yLAfUtufH8cdLybrdWPc6U+xRuhDhqqrEcBO5+eob2xyqEaNk\n"
+"nIV/86724zPptGRahWz0rzW2PvNppJdNBg==\n"
+"-----END EC PRIVATE KEY-----\n";
+
+/* Valid signed server certificate for server-2.unittest.o7s */
+static const char * crt_str = \
+"-----BEGIN CERTIFICATE-----\n"
+"MIIDgjCCAyigAwIBAgICEAIwCgYIKoZIzj0EAwIwWzELMAkGA1UEBhMCQkUxDDAK\n"
+"BgNVBAgMA09WTDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3Mx\n"
+"GTAXBgNVBAMMEGltMi51bml0dGVzdC5vN3MwHhcNMjUwNzA0MTMxODI5WhcNMzUw\n"
+"NzAyMTMxODI5WjBwMQswCQYDVQQGEwJCRTEMMAoGA1UECAwDT1ZMMQ4wDAYDVQQH\n"
+"DAVHaGVudDEMMAoGA1UECgwDbzdzMRUwEwYDVQQLDAx1bml0dGVzdC5vN3MxHjAc\n"
+"BgNVBAMMFXNlcnZlci0yLnVuaXR0ZXN0Lm83czBZMBMGByqGSM49AgEGCCqGSM49\n"
+"AwEHA0IABHAtMiwH1Lbnx/HHS8m63Vj3OlPsUboQ4aqqxHATufnqG9scqhGjZJyF\n"
+"f/Ou9uMz6bRkWoVs9K81tj7zaaSXTQajggHFMIIBwTAJBgNVHRMEAjAAMBEGCWCG\n"
+"SAGG+EIBAQQEAwIGQDA6BglghkgBhvhCAQ0ELRYrR3JpbGxlZCBDaGVlc2UgR2Vu\n"
+"ZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUTt3xHTwE9amoglxh\n"
+"cEMqWv+PpDMwgb8GA1UdIwSBtzCBtIAUFfeZRx8QWWKQr7Aw8zjDu2shvcShgZek\n"
+"gZQwgZExCzAJBgNVBAYTAkJFMQwwCgYDVQQIDANPVkwxDjAMBgNVBAcMBUdoZW50\n"
+"MQwwCgYDVQQKDANvN3MxFTATBgNVBAsMDHVuaXR0ZXN0Lm83czEZMBcGA1UEAwwQ\n"
+"Y2EyLnVuaXR0ZXN0Lm83czEkMCIGCSqGSIb3DQEJARYVZHVtbXlAb3Vyb2Jvcm9z\n"
+"LnJvY2tzggIQAjAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw\n"
+"EQYDVR0fBAowCDAGoASgAoYAMCoGCCsGAQUFBwEBBB4wHDAMBggrBgEFBQcwAoYA\n"
+"MAwGCCsGAQUFBzABhgAwIAYDVR0RBBkwF4IVc2VydmVyLTEudW5pdHRlc3Qubzdz\n"
+"MAoGCCqGSM49BAMCA0gAMEUCIQDHuDb62w/Uah4nKwUFoJVkr4rgdNGh2Rn3SWaK\n"
+"0FV/gAIgOLKorTwSgrTFdyOUkuPOhRs8BEMpah+dp8UTO8AnLvY=\n"
+"-----END CERTIFICATE-----\n";
+
+static int test_oap_hdr_init_fini(void)
+{
+ struct oap_hdr oap_hdr;
+ struct timespec now;
+ uint64_t stamp;
+ buffer_t ephkey = BUF_INIT;
+ buffer_t data = BUF_INIT;
+ uint8_t buf[OAP_ID_SIZE];
+ buffer_t id;
+ void * pkp = NULL;
+ void * pubcrt = NULL;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ clock_gettime(CLOCK_REALTIME, &now);
+ stamp = TS_TO_UINT64(now);
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to init OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE) {
+ printf("OAP request header wrong: %zu < %zu.\n",
+ oap_hdr.hdr.len, OAP_HDR_MIN_SIZE);
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.id.len != OAP_ID_SIZE) {
+ printf("OAP request header ID wrong size: %zu != %zu.\n",
+ oap_hdr.id.len, (size_t) OAP_ID_SIZE);
+ goto fail_req_hdr_chk;
+ }
+
+ if (memcmp(oap_hdr.id.data, id.data, OAP_ID_SIZE) != 0) {
+ printf("OAP request header ID mismatch.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.timestamp < stamp) {
+ printf("OAP request header timestamp is too old.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ if (oap_hdr.timestamp > stamp + 1 * BILLION) {
+ printf("OAP request header timestamp is too new.\n");
+ goto fail_req_hdr_chk;
+ }
+
+ oap_hdr_fini(&oap_hdr);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_req_hdr_chk:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_oap_hdr_init_fini_data(void)
+
+{
+ struct oap_hdr oap_hdr;
+ buffer_t data;
+ buffer_t ephkey = BUF_INIT;
+ uint8_t buf[OAP_ID_SIZE];
+ buffer_t id;
+ void * pkp = NULL;
+ void * pubcrt = NULL;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ data.len = 100;
+ data.data = malloc(data.len);
+ if (data.data == NULL) {
+ printf("Failed to allocate data buffer.\n");
+ goto fail_data;
+ }
+
+ random_buffer(data.data, data.len);
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to create OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.hdr.len != OAP_HDR_MIN_SIZE + data.len) {
+ printf("OAP request header wrong: %zu < %zu.\n",
+ oap_hdr.hdr.len, OAP_HDR_MIN_SIZE + data.len);
+ goto fail_req_hdr_sz;
+ }
+
+ freebuf(data);
+ oap_hdr_fini(&oap_hdr);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_req_hdr_sz:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ freebuf(data);
+ fail_data:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+static int test_oap_hdr_init_fini_signed(void)
+{
+ struct oap_hdr oap_hdr;
+ buffer_t ephkey = BUF_INIT;
+ buffer_t data = BUF_INIT;
+ buffer_t sign;
+ buffer_t id;
+ uint8_t buf[OAP_ID_SIZE];
+ void * pkp;
+ void * pk;
+ void * pubcrt;
+ void * pubcrt2;
+
+ TEST_START();
+
+ random_buffer(buf, OAP_ID_SIZE);
+ id.data = buf;
+ id.len = OAP_ID_SIZE;
+
+ if (crypt_load_privkey_str(pkp_str, &pkp) < 0) {
+ printf("Failed to load private key.\n");
+ goto fail_pkp;
+ }
+
+ if (crypt_load_crt_str(crt_str, &pubcrt) < 0) {
+ printf("Failed to load public certificate.\n");
+ goto fail_pubcrt;
+ }
+
+ if (oap_hdr_init(id, pkp, pubcrt, ephkey, data, &oap_hdr) < 0) {
+ printf("Failed to create OAP request header.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.crt.len == 0) {
+ printf("OAP request header has no public certificate.\n");
+ goto fail_req_hdr;
+ }
+
+ if (oap_hdr.sig.len == 0) {
+ printf("OAP request header no signature.\n");
+ goto fail_req_hdr;
+ }
+
+ if (crypt_load_crt_der(oap_hdr.crt, &pubcrt2) < 0) {
+ printf("Failed to load public certificate from DER.\n");
+ goto fail_crt_der;
+ }
+
+ if (crypt_get_pubkey_crt(pubcrt2, &pk) < 0) {
+ printf("Failed to get public key from certificate.\n");
+ goto fail_crt_pk;
+ }
+
+ sign = oap_hdr.hdr;
+ sign.len -= (oap_hdr.sig.len + sizeof(uint16_t));
+
+ if (auth_verify_sig(pk, sign, oap_hdr.sig) < 0) {
+ printf("Failed to verify OAP request header signature.\n");
+ goto fail_check_sig;
+ }
+
+ oap_hdr_fini(&oap_hdr);
+
+ crypt_free_crt(pubcrt2);
+ crypt_free_crt(pubcrt);
+ crypt_free_key(pk);
+ crypt_free_key(pkp);
+
+ TEST_SUCCESS();
+
+ return TEST_RC_SUCCESS;
+
+ fail_check_sig:
+ crypt_free_key(pk);
+ fail_crt_pk:
+ crypt_free_crt(pubcrt2);
+ fail_crt_der:
+ oap_hdr_fini(&oap_hdr);
+ fail_req_hdr:
+ crypt_free_crt(pubcrt);
+ fail_pubcrt:
+ crypt_free_key(pkp);
+ fail_pkp:
+ TEST_FAIL();
+ return TEST_RC_FAIL;
+}
+
+int oap_test(int argc,
+ char **argv)
+{
+ int ret = 0;
+
+ (void) argc;
+ (void) argv;
+
+ ret |= test_oap_hdr_init_fini();
+ ret |= test_oap_hdr_init_fini_data();
+#ifdef HAVE_OPENSSL
+ ret |= test_oap_hdr_init_fini_signed();
+#else
+ (void) test_oap_hdr_init_fini_signed;
+
+ ret = TEST_RC_SKIP;
+#endif
+ return ret;
+}