diff options
author | Dimitri Staessens <dimitri@ouroboros.rocks> | 2023-03-04 03:48:48 +0100 |
---|---|---|
committer | Sander Vrijders <sander@ouroboros.rocks> | 2023-03-08 15:59:37 +0100 |
commit | 89b58eaa2706c54aeb0a48252d1cfbd2b5ae01b7 (patch) | |
tree | 891c4a2de37e06fdb8879741911a6b7ff2f1b4b8 /src | |
parent | f16b4a1954ab4fbca0ec403f6a04c80375328921 (diff) | |
download | ouroboros-89b58eaa2706c54aeb0a48252d1cfbd2b5ae01b7.tar.gz ouroboros-89b58eaa2706c54aeb0a48252d1cfbd2b5ae01b7.zip |
irmd: Add configuration file support
This adds initial support for configuration files using the C99 TOML
parser (to be installed separately from https://github.com/cktan/tomlc99).
The default location for the IRMd configuration file is
/etc/ouroboros/irmd.conf. This is configurable at build time.
An example file will be installed in the configuration directory with
the name irmd.conf.example.
Config file support can be disabled using the DISABLE_CONFIGFILE build
option.
There were some refactors and changes to the configuration messages
and protobuf files. This works towards consolidation of protobuf C as
an option for more generic handling of serialization/deserialization
of various messages.
Signed-off-by: Dimitri Staessens <dimitri@ouroboros.rocks>
Signed-off-by: Sander Vrijders <sander@ouroboros.rocks>
Diffstat (limited to 'src')
-rw-r--r-- | src/ipcpd/broadcast/main.c | 2 | ||||
-rw-r--r-- | src/ipcpd/common/enroll.c | 241 | ||||
-rw-r--r-- | src/ipcpd/common/enroll.h | 4 | ||||
-rw-r--r-- | src/ipcpd/eth/eth.c | 7 | ||||
-rw-r--r-- | src/ipcpd/ipcp.c | 76 | ||||
-rw-r--r-- | src/ipcpd/ipcp.h | 2 | ||||
-rw-r--r-- | src/ipcpd/unicast/main.c | 2 | ||||
-rw-r--r-- | src/irmd/CMakeLists.txt | 37 | ||||
-rw-r--r-- | src/irmd/config.h.in | 6 | ||||
-rw-r--r-- | src/irmd/configfile.c | 837 | ||||
-rw-r--r-- | src/irmd/configfile.h | 29 | ||||
-rw-r--r-- | src/irmd/ipcp.c | 21 | ||||
-rw-r--r-- | src/irmd/ipcp.h | 7 | ||||
-rw-r--r-- | src/irmd/irmd.h | 61 | ||||
-rw-r--r-- | src/irmd/main.c | 150 | ||||
-rw-r--r-- | src/irmd/registry.c | 1 | ||||
-rw-r--r-- | src/irmd/utils.h | 2 | ||||
-rw-r--r-- | src/lib/CMakeLists.txt | 18 | ||||
-rw-r--r-- | src/lib/dev.c | 15 | ||||
-rw-r--r-- | src/lib/enroll.proto | 40 | ||||
-rw-r--r-- | src/lib/ipcp_config.proto | 18 | ||||
-rw-r--r-- | src/lib/ipcpd_messages.proto | 2 | ||||
-rw-r--r-- | src/lib/irm.c | 63 | ||||
-rw-r--r-- | src/lib/irmd_messages.proto | 2 | ||||
-rw-r--r-- | src/lib/protobuf.c | 438 | ||||
-rw-r--r-- | src/lib/serdes-oep.c | 155 | ||||
-rw-r--r-- | src/lib/sockets.c | 48 | ||||
-rw-r--r-- | src/tools/irm/irm_ipcp_bootstrap.c | 9 |
28 files changed, 1870 insertions, 423 deletions
diff --git a/src/ipcpd/broadcast/main.c b/src/ipcpd/broadcast/main.c index d0becc63..804741f0 100644 --- a/src/ipcpd/broadcast/main.c +++ b/src/ipcpd/broadcast/main.c @@ -139,7 +139,7 @@ static int broadcast_ipcp_enroll(const char * dst, goto fail_start_comp; } - if (enroll_done(&conn, 0)) + if (enroll_ack(&conn, 0)) log_warn("Failed to confirm enrollment with peer."); if (connmgr_dealloc(COMPID_ENROLL, &conn)) diff --git a/src/ipcpd/common/enroll.c b/src/ipcpd/common/enroll.c index 745829e7..32a5ed93 100644 --- a/src/ipcpd/common/enroll.c +++ b/src/ipcpd/common/enroll.c @@ -34,7 +34,7 @@ #include <ouroboros/dev.h> #include <ouroboros/logs.h> #include <ouroboros/errno.h> -#include <ouroboros/sockets.h> +#include <ouroboros/serdes-oep.h> #include "common/connmgr.h" #include "common/enroll.h" @@ -45,9 +45,6 @@ #include <string.h> #include <pthread.h> -#include "ipcp_config.pb-c.h" -typedef EnrollMsg enroll_msg_t; - #define ENROLL_COMP "Enrollment" #define ENROLL_PROTO "OEP" /* Ouroboros enrollment protocol */ #define ENROLL_WARN_TIME_OFFSET 20 @@ -67,56 +64,60 @@ struct { static int send_rcv_enroll_msg(int fd) { - enroll_msg_t req = ENROLL_MSG__INIT; - enroll_msg_t * reply; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; - ssize_t delta_t; - struct timespec t0; - struct timespec rtt; -#ifdef BUILD_IPCP_UNICAST - uni_config_msg_t * uni_cfg_msg; -#endif - req.code = ENROLL_CODE__ENROLL_REQ; - - len = enroll_msg__get_packed_size(&req); + uint8_t __buf[ENROLL_BUF_LEN]; + buffer_t buf; + buffer_t msg; + ssize_t len; + ssize_t delta_t; + struct timespec t0; + struct timespec rtt; + int ret; + struct enroll_resp resp; + + buf.data = __buf; + buf.len = sizeof(__buf); + + len = enroll_req_ser(buf); if (len < 0) { - log_dbg("Failed pack request message."); + log_dbg("Failed to pack request message."); return -1; } - enroll_msg__pack(&req, buf); - clock_gettime(CLOCK_REALTIME, &t0); - if (flow_write(fd, buf, len) < 0) { + log_dbg("Sending request message."); + + if (flow_write(fd, buf.data, len) < 0) { log_dbg("Failed to send request message."); return -1; } - len = flow_read(fd, buf, ENROLL_BUF_LEN); + log_dbg("Waiting for reply message."); + + len = flow_read(fd, buf.data, buf.len); if (len < 0) { - log_dbg("No enrollment reply received."); + log_dbg("No reply received."); return -1; } - log_dbg("Received enrollment info (%zd bytes).", len); + log_dbg("Received configuration info (%zd bytes).", len); + + msg.data = buf.data; + msg.len = len; - reply = enroll_msg__unpack(NULL, len, buf); - if (reply == NULL) { - log_dbg("No enrollment response."); + ret = enroll_resp_des(&resp, msg); + if (ret < 0) { + log_dbg("Failed to unpack response message."); return -1; } - if (reply->code != ENROLL_CODE__ENROLL_BOOT) { - log_dbg("Failed to unpack enrollment response."); - enroll_msg__free_unpacked(reply, NULL); + if (resp.response < 0) { + log_dbg("Remote denied request: %d.", resp.response); return -1; } - if (!(reply->has_t_sec && reply->has_t_nsec)) { - log_dbg("No time in response message."); - enroll_msg__free_unpacked(reply, NULL); + if (resp.conf.type != ipcpi.type) { + log_dbg("Wrong type in enrollment response %d (%d).", resp.conf.type, ipcpi.type); return -1; } @@ -124,168 +125,107 @@ static int send_rcv_enroll_msg(int fd) delta_t = ts_diff_ms(&t0, &rtt); - rtt.tv_sec = reply->t_sec; - rtt.tv_nsec = reply->t_nsec; + rtt.tv_sec = resp.t.tv_sec; + rtt.tv_nsec = resp.t.tv_nsec; if (labs(ts_diff_ms(&t0, &rtt)) - delta_t > ENROLL_WARN_TIME_OFFSET) log_warn("Clock offset above threshold."); - strcpy(enroll.conf.layer_info.layer_name, - reply->conf->layer_info->layer_name); - enroll.conf.type = reply->conf->ipcp_type; -#ifdef BUILD_IPCP_UNICAST - uni_cfg_msg = reply->conf->unicast; - - enroll.conf.unicast.dt.addr_size = uni_cfg_msg->dt->addr_size; - enroll.conf.unicast.dt.eid_size = uni_cfg_msg->dt->eid_size; - enroll.conf.unicast.dt.max_ttl = uni_cfg_msg->dt->max_ttl; - enroll.conf.unicast.dt.routing_type = uni_cfg_msg->dt->routing_type; - enroll.conf.unicast.addr_auth_type = uni_cfg_msg->addr_auth_type; - enroll.conf.unicast.cong_avoid = uni_cfg_msg->cong_avoid; -#endif - enroll.conf.layer_info.dir_hash_algo - = reply->conf->layer_info->dir_hash_algo; - enroll_msg__free_unpacked(reply, NULL); + enroll.conf = resp.conf; return 0; } -static ssize_t enroll_pack(uint8_t ** buf) -{ - enroll_msg_t msg = ENROLL_MSG__INIT; - ipcp_config_msg_t config = IPCP_CONFIG_MSG__INIT; - layer_info_msg_t layer_info = LAYER_INFO_MSG__INIT; -#ifdef BUILD_IPCP_UNICAST - dt_config_msg_t dt_cfg_msg = DT_CONFIG_MSG__INIT; - uni_config_msg_t uni_cfg_msg = UNI_CONFIG_MSG__INIT; -#endif - struct timespec now; - ssize_t len; - - clock_gettime(CLOCK_REALTIME, &now); - - msg.code = ENROLL_CODE__ENROLL_BOOT; - msg.has_t_sec = true; - msg.t_sec = now.tv_sec; - msg.has_t_nsec = true; - msg.t_nsec = now.tv_nsec; - - config.ipcp_type = enroll.conf.type; -#ifdef BUILD_IPCP_UNICAST - dt_cfg_msg.addr_size = enroll.conf.unicast.dt.addr_size; - dt_cfg_msg.eid_size = enroll.conf.unicast.dt.eid_size; - dt_cfg_msg.max_ttl = enroll.conf.unicast.dt.max_ttl; - dt_cfg_msg.routing_type = enroll.conf.unicast.dt.routing_type; - uni_cfg_msg.dt = &dt_cfg_msg; - uni_cfg_msg.addr_auth_type = enroll.conf.unicast.addr_auth_type; - uni_cfg_msg.cong_avoid = enroll.conf.unicast.cong_avoid; - config.unicast = &uni_cfg_msg; -#endif - layer_info.layer_name = (char *) enroll.conf.layer_info.layer_name; - layer_info.dir_hash_algo = enroll.conf.layer_info.dir_hash_algo; - - config.layer_info = &layer_info; - msg.conf = &config; - - len = enroll_msg__get_packed_size(&msg); - - *buf = malloc(len); - if (*buf == NULL) - return -ENOMEM; - - enroll_msg__pack(&msg, *buf); - - return len; -} static void * enroll_handle(void * o) { - struct conn conn; - uint8_t buf[ENROLL_BUF_LEN]; - uint8_t * reply; - ssize_t len; - enroll_msg_t * msg; + struct enroll_resp resp; + struct conn conn; + uint8_t __buf[ENROLL_BUF_LEN]; + buffer_t buf; + ssize_t len; + int response; (void) o; + buf.data = __buf; + buf.len = sizeof(__buf); + + resp.conf = enroll.conf; + while (true) { + buffer_t msg; + if (connmgr_wait(COMPID_ENROLL, &conn)) { log_err("Failed to get next connection."); continue; } - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); + log_info("New enrollment connection."); + + len = flow_read(conn.flow_info.fd, buf.data, buf.len); if (len < 0) { log_err("Failed to read from flow."); connmgr_dealloc(COMPID_ENROLL, &conn); continue; } - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } + log_dbg("Read request from flow (%zd bytes).", len); + msg.data = buf.data; + msg.len = (size_t) len; - if (msg->code != ENROLL_CODE__ENROLL_REQ) { - log_err("Wrong message type."); + if (enroll_req_des(msg) < 0) { + log_err("Failed to unpack request message."); connmgr_dealloc(COMPID_ENROLL, &conn); - enroll_msg__free_unpacked(msg, NULL); continue; } + /* TODO: authentication */ + log_dbg("Enrolling a new neighbor."); - enroll_msg__free_unpacked(msg, NULL); + clock_gettime(CLOCK_REALTIME, &resp.t); - len = enroll_pack(&reply); + resp.response = 0; + + len = enroll_resp_ser(&resp, buf); if (len < 0) { - log_err("Failed to pack enrollment message."); + log_err("Failed to pack reply."); connmgr_dealloc(COMPID_ENROLL, &conn); continue; } log_dbg("Sending enrollment info (%zd bytes).", len); - if (flow_write(conn.flow_info.fd, reply, len) < 0) { - log_err("Failed respond to enrollment request."); + if (flow_write(conn.flow_info.fd, buf.data, len) < 0) { + log_err("Failed respond to request."); connmgr_dealloc(COMPID_ENROLL, &conn); - free(reply); continue; } - free(reply); - - len = flow_read(conn.flow_info.fd, buf, ENROLL_BUF_LEN); + len = flow_read(conn.flow_info.fd, buf.data, buf.len); if (len < 0) { log_err("Failed to read from flow."); connmgr_dealloc(COMPID_ENROLL, &conn); continue; } - msg = enroll_msg__unpack(NULL, len, buf); - if (msg == NULL) { - log_err("Failed to unpack message."); - connmgr_dealloc(COMPID_ENROLL, &conn); - continue; - } + msg.data = buf.data; + msg.len = (size_t) len; - if (msg->code != ENROLL_CODE__ENROLL_DONE || !msg->has_result) { - log_err("Wrong message type."); - enroll_msg__free_unpacked(msg, NULL); + if (enroll_ack_des(&response, msg) < 0) { + log_err("Failed to unpack acknowledgment."); connmgr_dealloc(COMPID_ENROLL, &conn); continue; } - - if (msg->result == 0) - log_dbg("Neighbor enrollment successful."); + if (response == 0) + log_info("Neighbor enrollment successful."); else - log_dbg("Neigbor reported failed enrollment."); - - enroll_msg__free_unpacked(msg, NULL); + log_info("Neigbor enrolment failed at remote."); connmgr_dealloc(COMPID_ENROLL, &conn); + + log_info("Enrollment connection closed."); } return 0; @@ -293,36 +233,35 @@ static void * enroll_handle(void * o) int enroll_boot(struct conn * conn) { - log_dbg("Getting boot information."); + log_dbg("Starting enrollment."); if (send_rcv_enroll_msg(conn->flow_info.fd)) { log_err("Failed to enroll."); return -1; } + log_dbg("Enrollment complete."); + return 0; } -int enroll_done(struct conn * conn, - int result) +int enroll_ack(struct conn * conn, + int result) { - enroll_msg_t msg = ENROLL_MSG__INIT; - uint8_t buf[ENROLL_BUF_LEN]; - ssize_t len; + uint8_t __buf[ENROLL_BUF_LEN]; + buffer_t buf; + ssize_t len; - msg.code = ENROLL_CODE__ENROLL_DONE; - msg.has_result = true; - msg.result = result; + buf.data = __buf; + buf.len = sizeof(__buf); - len = enroll_msg__get_packed_size(&msg); + len = enroll_ack_ser(result, buf); if (len < 0) { - log_dbg("Failed pack request message."); + log_err("Failed to pack acknowledgement."); return -1; } - enroll_msg__pack(&msg, buf); - - if (flow_write(conn->flow_info.fd, buf, len) < 0) { + if (flow_write(conn->flow_info.fd, buf.data, len) < 0) { log_dbg("Failed to send acknowledgment."); return -1; } diff --git a/src/ipcpd/common/enroll.h b/src/ipcpd/common/enroll.h index bbb84561..fa22923f 100644 --- a/src/ipcpd/common/enroll.h +++ b/src/ipcpd/common/enroll.h @@ -39,8 +39,8 @@ void enroll_bootstrap(const struct ipcp_config * conf); int enroll_boot(struct conn * conn); -int enroll_done(struct conn * conn, - int result); +int enroll_ack(struct conn * conn, + int result); struct ipcp_config * enroll_get_conf(void); diff --git a/src/ipcpd/eth/eth.c b/src/ipcpd/eth/eth.c index 6e0cb179..6d9d78ba 100644 --- a/src/ipcpd/eth/eth.c +++ b/src/ipcpd/eth/eth.c @@ -1283,11 +1283,6 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) ipcpi.dir_hash_algo = conf->layer_info.dir_hash_algo; strcpy(ipcpi.layer_name, conf->layer_info.layer_name); - if (conf->eth.dev == NULL) { - log_err("Device name is NULL."); - return -1; - } - if (strlen(conf->eth.dev) >= IFNAMSIZ) { log_err("Invalid device name: %s.", conf->eth.dev); return -1; @@ -1298,7 +1293,7 @@ static int eth_ipcp_bootstrap(const struct ipcp_config * conf) #ifdef BUILD_ETH_DIX if (conf->eth.ethertype < 0x0600 || conf->eth.ethertype == 0xFFFF) { - log_err("Invalid Ethertype."); + log_err("Invalid Ethertype: %d.", conf->eth.ethertype); return -1; } eth_data.ethertype = htons(conf->eth.ethertype); diff --git a/src/ipcpd/ipcp.c b/src/ipcpd/ipcp.c index 5d9c6e7a..103c0804 100644 --- a/src/ipcpd/ipcp.c +++ b/src/ipcpd/ipcp.c @@ -47,6 +47,7 @@ #include <ouroboros/bitmap.h> #include <ouroboros/np1_flow.h> #include <ouroboros/rib.h> +#include <ouroboros/protobuf.h> #include <ouroboros/pthread.h> #include "ipcp.h" @@ -263,12 +264,9 @@ static void free_msg(void * o) static void handle_bootstrap(ipcp_config_msg_t * conf_msg, - layer_info_msg_t * layer_info_msg, ipcp_msg_t * ret_msg) { struct ipcp_config conf; - enum ipcp_type ipcp_type; - uni_config_msg_t * uni_cfg_msg; if (ipcpi.ops->ipcp_bootstrap == NULL) { log_err("Bootstrap unsupported."); @@ -282,58 +280,13 @@ static void handle_bootstrap(ipcp_config_msg_t * conf_msg, return; } - conf.type = conf_msg->ipcp_type; - - strcpy(conf.layer_info.layer_name, conf_msg->layer_info->layer_name); - - ipcp_type = conf_msg->ipcp_type; - - conf.layer_info.dir_hash_algo = conf_msg->layer_info->dir_hash_algo; - - switch(ipcp_type) { - case IPCP_LOCAL: - break; - case IPCP_UNICAST: - uni_cfg_msg = conf_msg->unicast; - - conf.unicast.dt.addr_size = uni_cfg_msg->dt->addr_size; - conf.unicast.dt.eid_size = uni_cfg_msg->dt->eid_size; - conf.unicast.dt.max_ttl = uni_cfg_msg->dt->max_ttl; - conf.unicast.dt.routing_type = uni_cfg_msg->dt->routing_type; - conf.unicast.addr_auth_type = uni_cfg_msg->addr_auth_type; - conf.unicast.cong_avoid = uni_cfg_msg->cong_avoid; - break; - case IPCP_ETH_DIX: - conf.eth.ethertype = conf_msg->eth->ethertype; - /* FALLTHRU */ - case IPCP_ETH_LLC: - conf.eth.dev = conf_msg->eth->dev; - break; - case IPCP_UDP: - conf.udp.ip_addr = conf_msg->udp->ip_addr; - conf.udp.dns_addr = conf_msg->udp->dns_addr; - conf.udp.port = conf_msg->udp->port; - conf.layer_info.dir_hash_algo = HASH_MD5; - break; - case IPCP_BROADCAST: - conf.layer_info.dir_hash_algo = HASH_SHA3_256; - break; - default: - log_err("Unknown IPCP type: %d.", conf_msg->ipcp_type); - ret_msg->result = -EIPCP; - return; - } - + conf = ipcp_config_msg_to_s(conf_msg); ret_msg->result = ipcpi.ops->ipcp_bootstrap(&conf); - if (ret_msg->result == 0) { - layer_info_msg->layer_name = strdup(conf.layer_info.layer_name); - layer_info_msg->dir_hash_algo = conf.layer_info.dir_hash_algo; - ret_msg->layer_info = layer_info_msg; - } + if (ret_msg->result == 0) + ret_msg->layer_info = layer_info_s_to_msg(&conf.layer_info); } static void handle_enroll(const char * dst, - layer_info_msg_t * layer_info_msg, ipcp_msg_t * ret_msg) { struct layer_info info; @@ -351,12 +304,8 @@ static void handle_enroll(const char * dst, } ret_msg->result = ipcpi.ops->ipcp_enroll(dst, &info); - if (ret_msg->result == 0) { - layer_info_msg->layer_name = strdup(info.layer_name); - layer_info_msg->dir_hash_algo = info.dir_hash_algo; - ret_msg->layer_info = layer_info_msg; - - } + if (ret_msg->result == 0) + ret_msg->layer_info = layer_info_s_to_msg(&info); } static void handle_connect(const char * dst, @@ -563,7 +512,6 @@ static void * mainloop(void * o) while (true) { ipcp_msg_t ret_msg = IPCP_MSG__INIT; - layer_info_msg_t layer_info_msg = LAYER_INFO_MSG__INIT; qosspec_t qs; struct cmd * cmd; @@ -600,13 +548,13 @@ static void * mainloop(void * o) switch (msg->code) { case IPCP_MSG_CODE__IPCP_BOOTSTRAP: - handle_bootstrap(msg->conf, &layer_info_msg, &ret_msg); + handle_bootstrap(msg->conf, &ret_msg); break; case IPCP_MSG_CODE__IPCP_ENROLL: - handle_enroll(msg->dst, &layer_info_msg, &ret_msg); + handle_enroll(msg->dst, &ret_msg); break; case IPCP_MSG_CODE__IPCP_CONNECT: - qs = msg_to_spec(msg->qosspec); + qs = qos_spec_msg_to_s(msg->qosspec); handle_connect(msg->dst, msg->comp, qs, &ret_msg); break; case IPCP_MSG_CODE__IPCP_DISCONNECT: @@ -628,7 +576,7 @@ static void * mainloop(void * o) assert(msg->hash.len == ipcp_dir_hash_len()); assert(msg->pk.len > 0 ? msg->pk.data != NULL : msg->pk.data == NULL); - qs = msg_to_spec(msg->qosspec); + qs = qos_spec_msg_to_s(msg->qosspec); handle_flow_alloc(msg->pid, msg->flow_id, msg->hash.data, qs, msg->pk.data, msg->pk.len, @@ -636,7 +584,7 @@ static void * mainloop(void * o) break; case IPCP_MSG_CODE__IPCP_FLOW_JOIN: assert(msg->hash.len == ipcp_dir_hash_len()); - qs = msg_to_spec(msg->qosspec); + qs = qos_spec_msg_to_s(msg->qosspec); handle_flow_join(msg->pid, msg->flow_id, msg->hash.data, qs, &ret_msg); break; @@ -680,7 +628,7 @@ static void * mainloop(void * o) ipcp_msg__pack(&ret_msg, buffer.data); if (ret_msg.layer_info != NULL) - free(ret_msg.layer_info->layer_name); + layer_info_msg__free_unpacked(ret_msg.layer_info, NULL); pthread_cleanup_push(__cleanup_close_ptr, &sfd); pthread_cleanup_push(free, buffer.data) diff --git a/src/ipcpd/ipcp.h b/src/ipcpd/ipcp.h index 9e7a7223..31d58ff2 100644 --- a/src/ipcpd/ipcp.h +++ b/src/ipcpd/ipcp.h @@ -26,6 +26,8 @@ #include <ouroboros/hash.h> #include <ouroboros/ipcp.h> #include <ouroboros/list.h> +#include <ouroboros/protobuf.h> +#include <ouroboros/qos.h> #include <ouroboros/sockets.h> #include <ouroboros/tpm.h> diff --git a/src/ipcpd/unicast/main.c b/src/ipcpd/unicast/main.c index 1318ec2f..8092449b 100644 --- a/src/ipcpd/unicast/main.c +++ b/src/ipcpd/unicast/main.c @@ -218,7 +218,7 @@ static int unicast_ipcp_enroll(const char * dst, goto fail_start_comp; } - if (enroll_done(&conn, 0)) + if (enroll_ack(&conn, 0)) log_warn("Failed to confirm enrollment with peer."); if (connmgr_dealloc(COMPID_ENROLL, &conn)) diff --git a/src/irmd/CMakeLists.txt b/src/irmd/CMakeLists.txt index 59d0d103..fb1e6ca2 100644 --- a/src/irmd/CMakeLists.txt +++ b/src/irmd/CMakeLists.txt @@ -4,6 +4,39 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${CMAKE_BINARY_DIR}/include) +find_library(TOML_LIBRARIES toml QUIET) +if (TOML_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) + message(STATUS "Found TOML C99 library: " ${TOML_LIBRARIES}) + message(STATUS "Configuration file support enabled") + message(STATUS "Configuration directory: ${OUROBOROS_CONFIG_DIR}") + set(INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}") + configure_file("${CMAKE_SOURCE_DIR}/irmd.conf.in" + "${CMAKE_BINARY_DIR}/irmd.conf.example" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/irmd.conf.example" + DESTINATION "${OUROBOROS_CONFIG_DIR}") + unset(INSTALL_DIR) + mark_as_advanced(TOML_LIBRARIES) + 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 () + message(STATUS "Install tomlc99 for config file support") + message(STATUS " https://github.com/cktan/tomlc99") + unset(DISABLE_CONFIGFILE CACHE) + unset(HAVE_TOML) +endif () + set(IRMD_REQ_ARR_TIMEOUT 500 CACHE STRING "Timeout for an application to respond to a new flow (ms)") set(IRMD_FLOW_TIMEOUT 5000 CACHE STRING @@ -31,6 +64,7 @@ set(SOURCE_FILES proc_table.c prog_table.c ipcp.c + configfile.c irm_flow.c main.c registry.c @@ -39,7 +73,8 @@ set(SOURCE_FILES add_executable (irmd ${SOURCE_FILES}) -target_link_libraries (irmd LINK_PUBLIC ouroboros-common) +target_link_libraries (irmd LINK_PUBLIC ouroboros-common + ${TOML_LIBRARIES} ${CONFINI_LIBRARIES}) include(AddCompileFlags) if (CMAKE_BUILD_TYPE MATCHES "Debug*") diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in index a6979504..10ccaa52 100644 --- a/src/irmd/config.h.in +++ b/src/irmd/config.h.in @@ -47,9 +47,15 @@ #define IRMD_MIN_THREADS @IRMD_MIN_THREADS@ #define IRMD_ADD_THREADS @IRMD_ADD_THREADS@ +#define OUROBOROS_CONFIG_DIR "@OUROBOROS_CONFIG_DIR@" +#define OUROBOROS_CONFIG_FILE "@OUROBOROS_CONFIG_FILE@" + #cmakedefine HAVE_FUSE #ifdef HAVE_FUSE #define FUSE_PREFIX "@FUSE_PREFIX@" #endif +#cmakedefine HAVE_TOML +#cmakedefine HAVE_CONFINI +#cmakedefine OUROBOROS_CONFIG_INI #cmakedefine HAVE_LIBGCRYPT diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c new file mode 100644 index 00000000..787edb49 --- /dev/null +++ b/src/irmd/configfile.c @@ -0,0 +1,837 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2023 + * + * The IPC Resource Manager / Configuration from file + * + * 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" + +#if defined (HAVE_TOML) + +#define _XOPEN_SOURCE 500 + +#define OUROBOROS_PREFIX "irmd/configuration" + +#include <toml.h> + +#include <assert.h> +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> + +#include <ouroboros/errno.h> +#include <ouroboros/ipcp.h> +#include <ouroboros/logs.h> + +#include "irmd.h" +#include "configfile.h" +#include "utils.h" + +#define ERRBUFSZ 200 + +static int toml_hash(toml_table_t * table, + struct layer_info * info) +{ + toml_datum_t hash; + + hash = toml_string_in(table, "hash"); + if (!hash.ok) { + log_dbg("No hash specified, using default."); + return 0; + } + + if (strcmp(hash.u.s, "SHA3_224") == 0) { + info->dir_hash_algo = DIR_HASH_SHA3_224; + } else if (strcmp(hash.u.s, "SHA3_256") == 0) { + info->dir_hash_algo = DIR_HASH_SHA3_256; + } else if (strcmp(hash.u.s, "SHA3_384") == 0) { + info->dir_hash_algo = DIR_HASH_SHA3_384; + } else if (strcmp(hash.u.s, "SHA3_512") == 0) { + info->dir_hash_algo = DIR_HASH_SHA3_512; + } else { + log_err("Unknown hash algorithm: %s.", hash.u.s); + free(hash.u.s); + return -1; + } + + free(hash.u.s); + + return 0; +} + +static int toml_local(toml_table_t * table, + struct ipcp_config * conf) +{ + *conf = local_default_conf; + + return toml_hash(table, &conf->layer_info); +} + +static int toml_eth_dev(toml_table_t * table, + struct eth_config * conf) +{ + toml_datum_t dev; + + dev = toml_string_in(table, "dev"); + if (!dev.ok) { + log_err("Missing device."); + return -1; + } + + if (strlen(dev.u.s) > DEV_NAME_SIZE) { + log_err("Device name too long: %s", dev.u.s); + free(dev.u.s); + return -1; + } + + strcpy(conf->dev, dev.u.s); + free(dev.u.s); + + return 0; +} + +static int toml_eth_llc(toml_table_t * table, + struct ipcp_config * conf) +{ + *conf = eth_llc_default_conf; + + if (toml_hash(table, &conf->layer_info) < 0) + return -1; + + return toml_eth_dev(table, &conf->eth); +} + + +static int toml_ethertype(toml_table_t * table, + struct eth_config * conf) +{ + toml_datum_t ethertype; + + ethertype = toml_int_in(table, "ethertype"); + if (ethertype.ok) + conf->ethertype = ethertype.u.i; + + if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF) + return -1; + + return 0; +} + +static int toml_eth_dix(toml_table_t * table, + struct ipcp_config * conf) +{ + *conf = eth_dix_default_conf; + + if (toml_hash(table, &conf->layer_info) < 0) + return -1; + + if (toml_eth_dev(table, &conf->eth) < 0) + return -1; + + if (toml_ethertype(table, &conf->eth) < 0) { + log_err("Ethertype not in valid range."); + return -1; + } + + return 0; +} + +static int toml_udp(toml_table_t * table, + struct ipcp_config * conf) +{ + toml_datum_t ip; + toml_datum_t port; + toml_datum_t dns; + + *conf = udp_default_conf; + + 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, &conf->udp.ip_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; + + dns = toml_string_in(table, "dns"); + if (dns.ok) { + if (inet_pton(AF_INET, dns.u.s, &conf->udp.dns_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_broadcast(toml_table_t * table, + struct ipcp_config * conf) +{ + (void) table; + (void) conf; + + /* Nothing to do here. */ + + return 0; +} + +static int toml_routing(toml_table_t * table, + struct dt_config * conf) +{ + toml_datum_t routing; + + 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; + free(routing.u.s); + } + + if (conf->routing_type == ROUTING_INVALID) + return -1; + + return 0; +} + +static int toml_addr_auth(toml_table_t * table, + struct uni_config * conf) +{ + toml_datum_t addr_auth; + + addr_auth = toml_string_in(table, "addr-auth"); + if (addr_auth.ok) { + if (strcmp(addr_auth.u.s, "flat") == 0) + conf->addr_auth_type = ADDR_AUTH_FLAT_RANDOM; + else + conf->addr_auth_type = ADDR_AUTH_INVALID; + free(addr_auth.u.s); + } + + if (conf->addr_auth_type == ADDR_AUTH_INVALID) + return -1; + + return 0; +} + +static int toml_congestion(toml_table_t * table, + struct uni_config * conf) +{ + toml_datum_t congestion; + + congestion = toml_string_in(table, "congestion"); + if (congestion.ok) { + if (strcmp(congestion.u.s, "none") == 0) + conf->cong_avoid = CA_NONE; + else if (strcmp(congestion.u.s, "lfa") == 0) + conf->cong_avoid = CA_MB_ECN; + else + conf->cong_avoid = CA_INVALID; + free(congestion.u.s); + + } + + if (conf->cong_avoid == CA_INVALID) + return -1; + + return 0; +} + +static int toml_dt(toml_table_t * table, + struct dt_config * conf) +{ + toml_datum_t addr; + toml_datum_t eid; + toml_datum_t ttl; + + addr = toml_int_in(table, "addr_size"); + if (addr.ok) + conf->addr_size = addr.u.i; + + eid = toml_int_in(table, "eid_size"); + if (eid.ok) + conf->eid_size = eid.u.i; + + ttl = toml_int_in(table, "max_ttl"); + if (ttl.ok) + conf->max_ttl = ttl.u.i; + + if (toml_routing(table, conf) < 0) { + log_err("Invalid routing option."); + return -1; + } + + return 0; +} + +static int toml_unicast(toml_table_t * table, + struct ipcp_config * conf) +{ + + + *conf = uni_default_conf; + + if (toml_hash(table, &conf->layer_info) < 0) + return -1; + + if (toml_dt(table, &conf->unicast.dt) < 0) { + log_err("Invalid DT configuration."); + return -1; + } + + if (toml_addr_auth(table, &conf->unicast) < 0) { + log_err("Invalid address authority"); + return -1; + } + + if (toml_congestion(table, &conf->unicast) < 0) { + log_err("Invalid congestion avoidance algorithm."); + return -1; + } + + return 0; +} + +static int toml_autobind(toml_table_t * table, + pid_t pid, + const char * name, + const char * layer) +{ + toml_datum_t autobind; + + autobind = toml_bool_in(table, "autobind"); + if (!autobind.ok) + return 0; + + if (bind_process(pid, name) < 0) { + log_err("Failed to bind IPCP process %d to %s.", pid, name); + return -1; + } + + if (layer != NULL && bind_process(pid, layer) < 0) { + log_err("Failed to bind IPCP process %d to %s.", pid, layer); + return -1; + } + + return 0; +} + +static int toml_register(toml_table_t * table, + pid_t pid) +{ + toml_array_t * reg; + int i; + int ret = 0; + + reg = toml_array_in(table, "reg"); + if (reg == NULL) + return 0; + + for (i = 0; ret == 0; i++) { + toml_datum_t name; + + name = toml_string_at(reg, i); + if (!name.ok) + break; + + log_dbg("Registering %s in %d", name.u.s, pid); + + ret = name_create(name.u.s, LB_SPILL); + if (ret < 0 && ret != -ENAME) { + free(name.u.s); + break; + } + + ret = name_reg(name.u.s, pid); + free(name.u.s); + } + + return ret; +} + +static int toml_connect(toml_table_t * table, + pid_t pid) +{ + toml_array_t * conn; + int i; + int ret = 0; + + conn = toml_array_in(table, "conn"); + if (conn == NULL) + return 0; + + for (i=0; ret == 0; i++) { + toml_datum_t dst; + qosspec_t qs = qos_raw; + + dst = toml_string_at(conn, i); + if (!dst.ok) + break; + + log_dbg("Connecting %d to %s", pid, dst.u.s); + + ret = connect_ipcp(pid, dst.u.s, MGMT_COMP, qs); + if (ret == 0) + ret = connect_ipcp(pid, dst.u.s, DT_COMP, qs); + + free(dst.u.s); + } + + return ret; +} + +static int toml_ipcp(toml_table_t * table, + const char * name, + struct ipcp_config * conf) +{ + toml_datum_t bootstrap; + toml_datum_t enrol; + pid_t pid; + int ret; + + log_dbg("Found IPCP %s in configuration file.", name); + + pid = create_ipcp(name, conf->type); + if (pid < 0) { + log_err("Failed to create IPCP %s.", name); + return -1; + } + + bootstrap = toml_string_in(table, "bootstrap"); + enrol = toml_string_in(table, "enrol"); + + if (bootstrap.ok && enrol.ok) { + log_err("Ignoring bootstrap for IPCP %s.", name); + free(bootstrap.u.s); + bootstrap.ok = false; + } + + if (!bootstrap.ok && !enrol.ok) { + log_dbg("Nothing more to do for %s.", name); + return 0; + } + + if (enrol.ok) { + char layer[LAYER_NAME_SIZE + 1]; + ret = enroll_ipcp(pid, enrol.u.s); + free(enrol.u.s); + if (ret < 0) { + log_err("Failed to enrol %s.", name); + return -1; + } + + if (get_layer_for_ipcp(pid, layer) < 0) + return -1; + + if (toml_autobind(table, pid, name, layer)) + return -1; + + if (toml_register(table, pid) < 0) { + log_err("Failed to register names."); + return -1; + } + + if (toml_connect(table, pid) < 0) { + log_err("Failed to register names."); + return -1; + } + + return 0; + } + + assert(bootstrap.ok); + + if (strlen(bootstrap.u.s) > LAYER_NAME_SIZE) { + log_err("Layer name too long: %s", bootstrap.u.s); + free(bootstrap.u.s); + return -1; + } + + switch (conf->type) { + case IPCP_LOCAL: + ret = toml_local(table, conf); + break; + case IPCP_ETH_DIX: + ret = toml_eth_dix(table, conf); + break; + case IPCP_ETH_LLC: + ret = toml_eth_llc(table, conf); + break; + case IPCP_UDP: + ret = toml_udp(table, conf); + break; + case IPCP_BROADCAST: + ret = toml_broadcast(table, conf); + break; + case IPCP_UNICAST: + ret = toml_unicast(table, conf); + break; + default: + log_err("Invalid IPCP type"); + ret = -1; + } + + if (ret < 0) + return -1; + + strcpy(conf->layer_info.layer_name, bootstrap.u.s); + free(bootstrap.u.s); + + if (bootstrap_ipcp(pid, conf) < 0) + return -1; + + if (toml_autobind(table, pid, name, conf->layer_info.layer_name) < 0) + return -1; + + if (toml_register(table, pid) < 0) { + log_err("Failed to register names."); + return -1; + } + + return 0; +} + +static int toml_ipcp_list(toml_table_t * table, + enum ipcp_type type) +{ + int i = 0; + int ret = 0; + + for (i = 0; ret == 0; i++) { + const char * key; + struct ipcp_config conf; + + key = toml_key_in(table, i); + if (key == NULL) + break; + + memset(&conf, 0, sizeof(conf)); + + conf.type = type; + + ret = toml_ipcp(toml_table_in(table, key), key, &conf); + } + + return ret; +} + +static int args_to_argv(const char * args, + char *** argv) +{ + char * tok; + char * str; + int argc = 0; + + str = (char *) args; + + tok = strtok(str, " "); + while (tok != NULL) { + tok = strtok(NULL, " "); + argc++; + } + + *argv = malloc((argc + 1) * sizeof(**argv)); + if (*argv == NULL) + goto fail_malloc; + + argc = 0; + tok = strtok(str, " "); + while (tok != NULL) { + (*argv)[argc] = malloc((strlen(tok) + 1) * sizeof(***argv)); + if (*argv[argc] == NULL) + goto fail_malloc2; + + strcpy((*argv)[argc++], tok); + tok = strtok(NULL, " "); + } + + (*argv)[argc] = NULL; + + return argc; + + fail_malloc2: + argvfree(*argv); + fail_malloc: + return -1; + +} + +static int toml_prog(char * prog, + const char * args, + const char * name) +{ + uint16_t flags = 0; + int argc = 0; + char ** argv; + int ret; + + if (args != NULL) + flags |= BIND_AUTO; + + argc = args_to_argv(args, &argv); + if (argc < 0) { + log_err("Failed to parse arguments: %s", args); + return -1; + } + + ret = bind_program(prog, name, flags, argc, argv); + if (ret < 0) + log_err("Failed to bind program %s %s for name %s.", + prog, args, name); + + argvfree(argv); + + return ret; +} + +static int toml_prog_list(toml_array_t * progs, + toml_array_t * args, + const char * name) +{ + int ret = 0; + int i; + + for (i = 0; ret == 0; i++) { + toml_datum_t prog; + toml_datum_t arg; + + prog = toml_string_at(progs, i); + if (!prog.ok) + break; + + if (args == NULL) { + ret = toml_prog(prog.u.s, NULL, name); + } else { + arg = toml_string_at(args, i); + if (!arg.ok) { + args = NULL; /* no more arguments in list. */ + assert(arg.u.s == NULL); + } + + ret = toml_prog(prog.u.s, arg.u.s, name); + + if (arg.ok) + free(arg.u.s); + } + + free(prog.u.s); + } + + return ret; +} + +static int toml_name(toml_table_t * table, + const char * name) +{ + toml_array_t * progs; + toml_array_t * args; + toml_datum_t lb; + enum pol_balance lb_pol = LB_SPILL; + + log_dbg("Found service name %s in configuration file.", name); + + lb = toml_string_in(table, "lb"); + if (lb.ok) { + if (strcmp(lb.u.s, "spill") == 0) + lb_pol = LB_SPILL; + else if (strcmp(lb.u.s, "round-robin") == 0) + lb_pol = LB_RR; + else + lb_pol = LB_INVALID; + free(lb.u.s); + } + + if (lb_pol == LB_INVALID) { + log_err("Invalid load-balancing policy for %s.", name); + return -1; + } + + if (name_create(name, lb_pol) < 0) { + log_err("Failed to create name %s.", name); + return -1; + } + + progs = toml_array_in(table, "prog"); + if (progs == NULL) + return 0; + + args = toml_array_in(table, "args"); + if (toml_prog_list(progs, args, name) < 0) + return -1; + + return 0; +} + +static int toml_name_list(toml_table_t * table) +{ + int i = 0; + int ret = 0; + + for (i = 0; ret == 0; i++) { + const char * key; + + key = toml_key_in(table, i); + if (key == NULL) + break; + + ret = toml_name(toml_table_in(table, key), key); + } + + return ret; + return 0; +} + +static int toml_toplevel(toml_table_t * table, + const char * key) +{ + toml_table_t * subtable; + + subtable = toml_table_in(table, key); + + 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, "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); + return -1; +} + +static int toml_load(toml_table_t * table) +{ + int i = 0; + int ret = 0; + + for (i = 0; ret == 0; i++) { + const char * key; + + key = toml_key_in(table, i); + if (key == NULL) + break; + + ret = toml_toplevel(table, key); + } + + return ret; +} + +static int toml_cfg(FILE * fp) +{ + toml_table_t * table; + char errbuf[ERRBUFSZ + 1]; + + assert(fp != NULL); + + table = toml_parse_file(fp, errbuf, sizeof(errbuf)); + if (table == NULL) { + log_err("Failed to parse config file: %s.", errbuf); + goto fail_parse; + } + + if (toml_load(table) < 0) { + log_err("Failed to load configuration."); + goto fail_load; + } + + toml_free(table); + + return 0; + + fail_load: + toml_free(table); + fail_parse: + return -1; +} + +int irm_configure(const char * path) +{ + FILE * fp; + char * rp; + + if (path == NULL) + return 0; + + rp = realpath(path, NULL); + if (rp == NULL) { + log_warn("Failed to resolve path for %s", path); + return 0; + } + + log_info("Reading configuration from file %s", rp); + + fp = fopen(rp, "r"); + if (fp == NULL) { + log_err("Failed to open config file: %s\n", strerror(errno)); + goto fail_fopen; + } + + if (toml_cfg(fp) < 0) { + log_err("Failed to load config file."); + goto fail_cfg; + } + + fclose(fp); + free(rp); + + return 0; + + fail_cfg: + fclose(fp); + fail_fopen: + free(rp); + return -1; +} + +#endif /* HAVE_TOML */ diff --git a/src/irmd/configfile.h b/src/irmd/configfile.h new file mode 100644 index 00000000..586bff96 --- /dev/null +++ b/src/irmd/configfile.h @@ -0,0 +1,29 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2023 + * + * The IPC Resource Manager / Configuration from file + * + * 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_CONFIGURATION_H +#define OUROBOROS_IRMD_CONFIGURATION_H + +int irm_configure(const char * path); + +#endif /* OUROBOROS_IRMD_CONFIGURATION_H */ diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c index 182fb087..c062809c 100644 --- a/src/irmd/ipcp.c +++ b/src/irmd/ipcp.c @@ -20,7 +20,7 @@ * Foundation, Inc., http://www.fsf.org/about/contact/. */ -#define _POSIX_C_SOURCE 199309L +#define _POSIX_C_SOURCE 200112L #include "config.h" @@ -194,9 +194,9 @@ int ipcp_destroy(pid_t pid) return 0; } -int ipcp_bootstrap(pid_t pid, - ipcp_config_msg_t * conf, - struct layer_info * info) +int ipcp_bootstrap(pid_t pid, + struct ipcp_config * conf, + struct layer_info * info) { ipcp_msg_t msg = IPCP_MSG__INIT; ipcp_msg_t * recv_msg = NULL; @@ -206,9 +206,10 @@ int ipcp_bootstrap(pid_t pid, return -EINVAL; msg.code = IPCP_MSG_CODE__IPCP_BOOTSTRAP; - msg.conf = conf; + msg.conf = ipcp_config_s_to_msg(conf); recv_msg = send_recv_ipcp_msg(pid, &msg); + ipcp_config_msg__free_unpacked(msg.conf, NULL); if (recv_msg == NULL) return -EIPCP; @@ -285,7 +286,6 @@ int ipcp_connect(pid_t pid, qosspec_t qs) { ipcp_msg_t msg = IPCP_MSG__INIT; - qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT; int ret = -1; ipcp_msg_t * recv_msg; @@ -294,10 +294,10 @@ int ipcp_connect(pid_t pid, msg.comp = (char *) component; msg.has_pid = true; msg.pid = pid; - qs_msg = spec_to_msg(&qs); - msg.qosspec = &qs_msg; + msg.qosspec = qos_spec_s_to_msg(&qs); recv_msg = send_recv_ipcp_msg(pid, &msg); + free(msg.qosspec); if (recv_msg == NULL) return -EIPCP; @@ -438,7 +438,6 @@ static int __ipcp_flow_alloc(pid_t pid, size_t dlen) { ipcp_msg_t msg = IPCP_MSG__INIT; - qosspec_msg_t qs_msg; ipcp_msg_t * recv_msg = NULL; int ret = -1; @@ -453,13 +452,13 @@ static int __ipcp_flow_alloc(pid_t pid, msg.has_hash = true; msg.hash.len = len; msg.hash.data = (uint8_t *) dst; - qs_msg = spec_to_msg(&qs); - msg.qosspec = &qs_msg; + msg.qosspec = qos_spec_s_to_msg(&qs);; msg.has_pk = true; msg.pk.data = (uint8_t *) data; msg.pk.len = (uint32_t) dlen; recv_msg = send_recv_ipcp_msg(pid, &msg); + free(msg.qosspec); if (recv_msg == NULL) return -EIPCP; diff --git a/src/irmd/ipcp.h b/src/irmd/ipcp.h index 40347e86..ad96ad1c 100644 --- a/src/irmd/ipcp.h +++ b/src/irmd/ipcp.h @@ -21,6 +21,7 @@ */ #include <ouroboros/ipcp.h> +#include <ouroboros/protobuf.h> #include <ouroboros/sockets.h> #include <sys/types.h> @@ -37,9 +38,9 @@ int ipcp_enroll(pid_t pid, const char * dst, struct layer_info * info); -int ipcp_bootstrap(pid_t pid, - ipcp_config_msg_t * conf, - struct layer_info * info); +int ipcp_bootstrap(pid_t pid, + struct ipcp_config * conf, + struct layer_info * info); int ipcp_connect(pid_t pid, const char * dst, diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h new file mode 100644 index 00000000..92c26818 --- /dev/null +++ b/src/irmd/irmd.h @@ -0,0 +1,61 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2023 + * + * The IPC Resource Manager + * + * 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_H +#define OUROBOROS_IRMD_H + +#include <ouroboros/ipcp.h> +#include <ouroboros/irm.h> + +int create_ipcp(const char * name, + enum ipcp_type type); + +int bootstrap_ipcp(pid_t pid, + struct ipcp_config * conf); + +int enroll_ipcp(pid_t pid, + const char * dst); + +int connect_ipcp(pid_t pid, + const char * dst, + const char * component, + qosspec_t qs); + +int get_layer_for_ipcp(pid_t pid, + char * buf); + +int name_create(const char * name, + enum pol_balance pol); + +int name_reg(const char * name, + pid_t pid); + +int bind_process(pid_t pid, + const char * name); + +int bind_program(char * prog, + const char * name, + uint16_t flags, + int argc, + char ** argv); + +#endif /* OUROBOROS_IRMD_H*/
\ No newline at end of file diff --git a/src/irmd/main.c b/src/irmd/main.c index 4277be3d..b2f83388 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -49,9 +49,11 @@ #include "utils.h" #include "registry.h" +#include "irmd.h" #include "irm_flow.h" #include "proc_table.h" #include "ipcp.h" +#include "configfile.h" #include <sys/socket.h> #include <sys/un.h> @@ -123,7 +125,9 @@ struct { struct bmp * flow_ids; /* flow_ids for flows */ struct list_head irm_flows; /* flow information */ pthread_rwlock_t flows_lock; /* lock for flows */ - +#ifdef HAVE_TOML + char * cfg_file; /* configuration file path */ +#endif struct lockfile * lf; /* single irmd per system */ struct shm_rdrbuff * rdrb; /* rdrbuff for packets */ @@ -363,7 +367,7 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const char * name, list_for_each_safe(p, h, &irmd.ipcps) { struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next); - if (e->layer == NULL || e->pid == src) + if (e->layer == NULL || e->pid == src || e->type == IPCP_BROADCAST) continue; len = IPCP_HASH_LEN(e); @@ -395,8 +399,31 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const char * name, return NULL; } -static pid_t create_ipcp(const char * name, - enum ipcp_type type) +int get_layer_for_ipcp(pid_t pid, + char * buf) +{ + struct ipcp_entry * entry; + + pthread_rwlock_rdlock(&irmd.reg_lock); + + entry = get_ipcp_entry_by_pid(pid); + if (entry == NULL || entry->layer == NULL) + goto fail; + + strcpy(buf, entry->layer); + + pthread_rwlock_unlock(&irmd.reg_lock); + + return 0; + + fail: + pthread_rwlock_unlock(&irmd.reg_lock); + return -1; +} + + +pid_t create_ipcp(const char * name, + enum ipcp_type type) { struct pid_el * ppid; struct ipcp_entry * entry; @@ -524,8 +551,8 @@ static int destroy_ipcp(pid_t pid) return 0; } -static int bootstrap_ipcp(pid_t pid, - ipcp_config_msg_t * conf) +int bootstrap_ipcp(pid_t pid, + struct ipcp_config * conf) { struct ipcp_entry * entry; struct layer_info info; @@ -539,7 +566,7 @@ static int bootstrap_ipcp(pid_t pid, return -1; } - if (entry->type != (enum ipcp_type) conf->ipcp_type) { + if (entry->type != conf->type) { pthread_rwlock_unlock(&irmd.reg_lock); log_err("Configuration does not match IPCP type."); return -1; @@ -563,13 +590,13 @@ static int bootstrap_ipcp(pid_t pid, pthread_rwlock_unlock(&irmd.reg_lock); log_info("Bootstrapped IPCP %d in layer %s.", - pid, conf->layer_info->layer_name); + pid, conf->layer_info.layer_name); return 0; } -static int enroll_ipcp(pid_t pid, - char * dst) +int enroll_ipcp(pid_t pid, + const char * dst) { struct ipcp_entry * entry = NULL; struct layer_info info; @@ -622,10 +649,10 @@ static int enroll_ipcp(pid_t pid, return 0; } -static int connect_ipcp(pid_t pid, - const char * dst, - const char * component, - qosspec_t qs) +int connect_ipcp(pid_t pid, + const char * dst, + const char * component, + qosspec_t qs) { struct ipcp_entry * entry = NULL; @@ -693,11 +720,11 @@ static int disconnect_ipcp(pid_t pid, return 0; } -static int bind_program(char * prog, - char * name, - uint16_t flags, - int argc, - char ** argv) +int bind_program(char * prog, + const char * name, + uint16_t flags, + int argc, + char ** argv) { char * progs; char ** argv_dup = NULL; @@ -719,21 +746,21 @@ static int bind_program(char * prog, return -ENOMEM; } - if ((flags & BIND_AUTO) && argc) { + if ((flags & BIND_AUTO) && argc > 0) { /* We need to duplicate argv and set argv[0] to prog. */ argv_dup = malloc((argc + 2) * sizeof(*argv_dup)); argv_dup[0] = strdup(prog); for (i = 1; i <= argc; ++i) { argv_dup[i] = strdup(argv[i - 1]); - if (argv_dup[i] == NULL) { - pthread_rwlock_unlock(&irmd.reg_lock); - argvfree(argv_dup); - log_err("Failed to bind program " - "%s to %s.", - prog, name); - free(progs); - return -ENOMEM; - } + if (argv_dup[i] != NULL) + continue; + + pthread_rwlock_unlock(&irmd.reg_lock); + log_err("Failed to bind program %s to %s.", + prog, name); + argvfree(argv_dup); + free(progs); + return -ENOMEM; } argv_dup[argc + 1] = NULL; } @@ -771,8 +798,8 @@ static int bind_program(char * prog, return 0; } -static int bind_process(pid_t pid, - char * name) +int bind_process(pid_t pid, + const char * name) { char * name_dup = NULL; struct proc_entry * e = NULL; @@ -952,8 +979,8 @@ static ssize_t list_ipcps(ipcp_info_msg_t *** ipcps, return -ENOMEM; } -static int name_create(const char * name, - enum pol_balance pol) +int name_create(const char * name, + enum pol_balance pol) { struct reg_entry * re; struct list_head * p; @@ -964,8 +991,8 @@ static int name_create(const char * name, if (registry_has_name(&irmd.registry, name)) { pthread_rwlock_unlock(&irmd.reg_lock); - log_err("Registry entry for %s already exists.", name); - return -ENAME; + log_warn("Registry entry for %s already exists.", name); + return 0; } re = registry_add_name(&irmd.registry, name); @@ -1084,8 +1111,8 @@ static ssize_t list_names(name_info_msg_t *** names, return -ENOMEM; } -static int name_reg(const char * name, - pid_t pid) +int name_reg(const char * name, + pid_t pid) { size_t len; struct ipcp_entry * ipcp; @@ -1403,8 +1430,7 @@ static int flow_alloc(pid_t pid, int state; uint8_t * hash; - log_info("Allocating flow for %d to %s.\n", - pid, dst); + log_info("Allocating flow for %d to %s.", pid, dst); ipcp = join ? get_ipcp_entry_by_layer(dst) : get_ipcp_by_dst_name(dst, pid); @@ -1967,12 +1993,13 @@ static void * mainloop(void * o) (void) o; while (true) { - irm_msg_t * ret_msg; - struct irm_flow e; - struct timespec * timeo = NULL; - struct timespec ts = {0, 0}; - struct cmd * cmd; - int result; + irm_msg_t * ret_msg; + struct irm_flow e; + struct ipcp_config conf; + struct timespec * timeo = NULL; + struct timespec ts = {0, 0}; + struct cmd * cmd; + int result; memset(&e, 0, sizeof(e)); @@ -2035,14 +2062,15 @@ static void * mainloop(void * o) result = destroy_ipcp(msg->pid); break; case IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP: - result = bootstrap_ipcp(msg->pid, msg->conf); + conf = ipcp_config_msg_to_s(msg->conf); + result = bootstrap_ipcp(msg->pid, &conf); break; case IRM_MSG_CODE__IRM_ENROLL_IPCP: result = enroll_ipcp(msg->pid, msg->dst); break; case IRM_MSG_CODE__IRM_CONNECT_IPCP: result = connect_ipcp(msg->pid, msg->dst, msg->comp, - msg_to_spec(msg->qosspec)); + qos_spec_msg_to_s(msg->qosspec)); break; case IRM_MSG_CODE__IRM_DISCONNECT_IPCP: result = disconnect_ipcp(msg->pid, msg->dst, msg->comp); @@ -2091,13 +2119,11 @@ static void * mainloop(void * o) result = flow_accept(msg->pid, timeo, &e, msg->pk.data, msg->pk.len); if (result == 0) { - qosspec_msg_t qs_msg; ret_msg->has_flow_id = true; ret_msg->flow_id = e.flow_id; ret_msg->has_pid = true; ret_msg->pid = e.n_1_pid; - qs_msg = spec_to_msg(&e.qs); - ret_msg->qosspec = &qs_msg; + ret_msg->qosspec = qos_spec_s_to_msg(&e.qs); ret_msg->has_pk = true; ret_msg->pk.data = e.data; ret_msg->pk.len = e.len; @@ -2109,7 +2135,7 @@ static void * mainloop(void * o) assert(msg->pk.len > 0 ? msg->pk.data != NULL : msg->pk.data == NULL); result = flow_alloc(msg->pid, msg->dst, - msg_to_spec(msg->qosspec), + qos_spec_msg_to_s(msg->qosspec), timeo, &e, false, msg->pk.data, msg->pk.len); if (result == 0) { @@ -2127,7 +2153,7 @@ static void * mainloop(void * o) case IRM_MSG_CODE__IRM_FLOW_JOIN: assert(msg->pk.len == 0 && msg->pk.data == NULL); result = flow_alloc(msg->pid, msg->dst, - msg_to_spec(msg->qosspec), + qos_spec_msg_to_s(msg->qosspec), timeo, &e, true, NULL, 0); if (result == 0) { ret_msg->has_flow_id = true; @@ -2150,7 +2176,7 @@ static void * mainloop(void * o) &e, msg->hash.data, msg->mpl, - msg_to_spec(msg->qosspec), + qos_spec_msg_to_s(msg->qosspec), msg->pk.data, msg->pk.len); if (result == 0) { @@ -2199,8 +2225,6 @@ static void * mainloop(void * o) irm_msg__pack(ret_msg, buffer.data); - /* Can't free the qosspec. */ - ret_msg->qosspec = NULL; irm_msg__free_unpacked(ret_msg, NULL); pthread_cleanup_push(__cleanup_close_ptr, &sfd); @@ -2493,6 +2517,9 @@ static int irm_init(void) static void usage(void) { printf("Usage: irmd \n" +#ifdef OUROBOROS_CONFIG_INI + " [--config <path> (Path to configuration file)]\n" +#endif " [--stdout (Log to stdout instead of system log)]\n" " [--version (Print version number and exit)]\n" "\n"); @@ -2566,6 +2593,9 @@ static void irm_stop(void) static void irm_argparse(int argc, char ** argv) { +#ifdef HAVE_TOML + irmd.cfg_file = OUROBOROS_CONFIG_DIR OUROBOROS_CONFIG_FILE; +#endif argc--; argv++; while (argc > 0) { @@ -2579,6 +2609,12 @@ static void irm_argparse(int argc, OUROBOROS_VERSION_MINOR, OUROBOROS_VERSION_PATCH); exit(EXIT_SUCCESS); +#ifdef HAVE_TOML + } else if (strcmp (*argv, "--config") == 0) { + irmd.cfg_file = *(argv + 1); + argc -= 2; + argv += 2; +#endif } else { usage(); exit(EXIT_FAILURE); @@ -2613,6 +2649,10 @@ int main(int argc, if (irm_start() < 0) goto fail_irm_start; +#ifdef HAVE_TOML + if (irm_configure(irmd.cfg_file) < 0) + irmd_set_state(IRMD_NULL); +#endif irm_sigwait(sigset); irm_stop(); diff --git a/src/irmd/registry.c b/src/irmd/registry.c index c68b9abc..0aebdab7 100644 --- a/src/irmd/registry.c +++ b/src/irmd/registry.c @@ -296,6 +296,7 @@ int reg_entry_add_pid(struct reg_entry * e, list_add(&i->next, &e->reg_pids); break; default: + free(i); assert(false); }; diff --git a/src/irmd/utils.h b/src/irmd/utils.h index 7fd72cd4..83585f21 100644 --- a/src/irmd/utils.h +++ b/src/irmd/utils.h @@ -23,6 +23,8 @@ #ifndef OUROBOROS_IRMD_UTILS_H #define OUROBOROS_IRMD_UTILS_H +#include <ouroboros/list.h> + #include <sys/types.h> struct str_el { diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 74fbb707..1a585249 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -4,13 +4,18 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_SOURCE_DIR}/include) include_directories(${CMAKE_BINARY_DIR}/include) -protobuf_generate_c(IRM_PROTO_SRCS IRM_PROTO_HDRS irmd_messages.proto) -protobuf_generate_c(IPCP_PROTO_SRCS IPCP_PROTO_HDRS ipcpd_messages.proto) protobuf_generate_c(QOSSPEC_PROTO_SRCS QOSSPEC_PROTO_HDRS qosspec.proto) -protobuf_generate_c(LAYER_CONFIG_PROTO_SRCS LAYER_CONFIG_PROTO_HDRS +protobuf_generate_c(IPCP_CONFIG_PROTO_SRCS IPCP_CONFIG_PROTO_HDRS ipcp_config.proto) -protobuf_generate_c(CACEP_PROTO_SRCS CACEP_PROTO_HDRS cacep.proto) +protobuf_generate_c(ENROLL_PROTO_SRCS ENROLL_PROTO_HDRS + enroll.proto) +protobuf_generate_c(CACEP_PROTO_SRCS CACEP_PROTO_HDRS + cacep.proto) +protobuf_generate_c(IRM_PROTO_SRCS IRM_PROTO_HDRS + irmd_messages.proto) +protobuf_generate_c(IPCP_PROTO_SRCS IPCP_PROTO_HDRS + ipcpd_messages.proto) if (NOT APPLE) find_library(LIBRT_LIBRARIES rt) @@ -253,9 +258,11 @@ set(SOURCE_FILES_COMMON logs.c md5.c notifier.c + protobuf.c qoscube.c random.c rib.c + serdes-oep.c sha3.c shm_flow_set.c shm_rbuff.c @@ -269,7 +276,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) add_library(ouroboros-common SHARED ${SOURCE_FILES_COMMON} ${IRM_PROTO_SRCS} - ${IPCP_PROTO_SRCS} ${LAYER_CONFIG_PROTO_SRCS} ${QOSSPEC_PROTO_SRCS}) + ${IPCP_PROTO_SRCS} ${IPCP_CONFIG_PROTO_SRCS} ${QOSSPEC_PROTO_SRCS} + ${ENROLL_PROTO_SRCS}) add_library(ouroboros-dev SHARED ${SOURCE_FILES_DEV} ${CACEP_PROTO_SRCS}) diff --git a/src/lib/dev.c b/src/lib/dev.c index c46bbdd7..e84efe55 100644 --- a/src/lib/dev.c +++ b/src/lib/dev.c @@ -39,6 +39,7 @@ #include <ouroboros/fccntl.h> #include <ouroboros/bitmap.h> #include <ouroboros/np1_flow.h> +#include <ouroboros/protobuf.h> #include <ouroboros/pthread.h> #include <ouroboros/random.h> #include <ouroboros/shm_flow_set.h> @@ -795,7 +796,7 @@ int flow_accept(qosspec_t * qs, crypt_dh_pkp_destroy(pkp); fd = flow_init(recv_msg->flow_id, recv_msg->pid, - msg_to_spec(recv_msg->qosspec), s, + qos_spec_msg_to_s(recv_msg->qosspec), s, recv_msg->mpl); irm_msg__free_unpacked(recv_msg, NULL); @@ -827,7 +828,6 @@ static int __flow_alloc(const char * dst, bool join) { irm_msg_t msg = IRM_MSG__INIT; - qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT; irm_msg_t * recv_msg; int fd; void * pkp = NULL; /* public key pair */ @@ -846,8 +846,7 @@ static int __flow_alloc(const char * dst, msg.dst = (char *) dst; msg.has_pid = true; msg.pid = getpid(); - qs_msg = spec_to_msg(qs); - msg.qosspec = &qs_msg; + msg.qosspec = qos_spec_s_to_msg(qs); if (timeo != NULL) { msg.has_timeo_sec = true; @@ -871,6 +870,8 @@ static int __flow_alloc(const char * dst, } recv_msg = send_recv_irm_msg(&msg); + qosspec_msg__free_unpacked(msg.qosspec, NULL); + if (recv_msg == NULL) goto fail_send; @@ -1832,7 +1833,6 @@ int ipcp_flow_req_arr(const uint8_t * dst, { irm_msg_t msg = IRM_MSG__INIT; irm_msg_t * recv_msg; - qosspec_msg_t qs_msg; int fd; assert(dst != NULL); @@ -1843,8 +1843,7 @@ int ipcp_flow_req_arr(const uint8_t * dst, msg.has_hash = true; msg.hash.len = len; msg.hash.data = (uint8_t *) dst; - qs_msg = spec_to_msg(&qs); - msg.qosspec = &qs_msg; + msg.qosspec = qos_spec_s_to_msg(&qs); msg.has_mpl = true; msg.mpl = mpl; msg.has_pk = true; @@ -1852,6 +1851,8 @@ int ipcp_flow_req_arr(const uint8_t * dst, msg.pk.len = dlen; recv_msg = send_recv_irm_msg(&msg); + qosspec_msg__free_unpacked(msg.qosspec, NULL); + if (recv_msg == NULL) return -EIRMD; diff --git a/src/lib/enroll.proto b/src/lib/enroll.proto new file mode 100644 index 00000000..34ca1847 --- /dev/null +++ b/src/lib/enroll.proto @@ -0,0 +1,40 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2023 + * + * Enrollment protocol + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +syntax = "proto2"; +import "ipcp_config.proto"; + +message enroll_req_msg { + /* TODO authentication */ + required uint32 magic = 1; +} + +message enroll_resp_msg { + required int64 t_sec = 1; + required int32 t_nsec = 2; + required int32 response = 3; + optional ipcp_config_msg conf = 4; +} + +message enroll_ack_msg { + required int32 response = 1; +} diff --git a/src/lib/ipcp_config.proto b/src/lib/ipcp_config.proto index c6481b09..1ff304f1 100644 --- a/src/lib/ipcp_config.proto +++ b/src/lib/ipcp_config.proto @@ -42,7 +42,7 @@ message uni_config_msg { message eth_config_msg { required string dev = 1; - optional uint32 ethertype = 2; + required uint32 ethertype = 2; } message udp_config_msg { @@ -53,22 +53,8 @@ message udp_config_msg { message ipcp_config_msg { required layer_info_msg layer_info = 1; - required int32 ipcp_type = 2; + required uint32 ipcp_type = 2; optional uni_config_msg unicast = 3; optional udp_config_msg udp = 4; optional eth_config_msg eth = 5; } - -enum enroll_code { - ENROLL_REQ = 1; - ENROLL_BOOT = 2; - ENROLL_DONE = 4; -}; - -message enroll_msg { - required enroll_code code = 1; - optional ipcp_config_msg conf = 2; - optional int64 t_sec = 3; - optional uint32 t_nsec = 4; - optional int32 result = 5; -};
\ No newline at end of file diff --git a/src/lib/ipcpd_messages.proto b/src/lib/ipcpd_messages.proto index c9853677..05831fa0 100644 --- a/src/lib/ipcpd_messages.proto +++ b/src/lib/ipcpd_messages.proto @@ -1,7 +1,7 @@ /* * Ouroboros - Copyright (C) 2016 - 2023 * - * IPCPd message + * Messages sent to IPCPds * * Dimitri Staessens <dimitri@ouroboros.rocks> * Sander Vrijders <sander@ouroboros.rocks> diff --git a/src/lib/irm.c b/src/lib/irm.c index 2a8aa05c..75071260 100644 --- a/src/lib/irm.c +++ b/src/lib/irm.c @@ -31,6 +31,7 @@ #include <ouroboros/irm.h> #include <ouroboros/utils.h> #include <ouroboros/sockets.h> +#include <ouroboros/protobuf.h> #include <stdbool.h> #include <string.h> @@ -98,15 +99,9 @@ int irm_destroy_ipcp(pid_t pid) int irm_bootstrap_ipcp(pid_t pid, const struct ipcp_config * conf) { - irm_msg_t msg = IRM_MSG__INIT; - ipcp_config_msg_t cfg_msg = IPCP_CONFIG_MSG__INIT; - layer_info_msg_t layer_info_msg = LAYER_INFO_MSG__INIT; - dt_config_msg_t dt_cfg_msg = DT_CONFIG_MSG__INIT; - uni_config_msg_t uni_cfg_msg = UNI_CONFIG_MSG__INIT; - eth_config_msg_t eth_cfg_msg = ETH_CONFIG_MSG__INIT; - udp_config_msg_t udp_cfg_msg = UDP_CONFIG_MSG__INIT; - irm_msg_t * recv_msg = NULL; - int ret = -1; + irm_msg_t msg = IRM_MSG__INIT; + irm_msg_t * recv_msg; + int ret; if (pid == -1 || conf == NULL) return -EINVAL; @@ -114,48 +109,10 @@ int irm_bootstrap_ipcp(pid_t pid, msg.code = IRM_MSG_CODE__IRM_BOOTSTRAP_IPCP; msg.has_pid = true; msg.pid = pid; - - cfg_msg.ipcp_type = conf->type; - layer_info_msg.layer_name = (char *) conf->layer_info.layer_name; - layer_info_msg.dir_hash_algo = conf->layer_info.dir_hash_algo; - - switch (conf->type) { - case IPCP_UNICAST: - dt_cfg_msg.addr_size = conf->unicast.dt.addr_size; - dt_cfg_msg.eid_size = conf->unicast.dt.eid_size; - dt_cfg_msg.max_ttl = conf->unicast.dt.max_ttl; - dt_cfg_msg.routing_type = conf->unicast.dt.routing_type; - uni_cfg_msg.dt = &dt_cfg_msg; - uni_cfg_msg.addr_auth_type = conf->unicast.addr_auth_type; - uni_cfg_msg.cong_avoid = conf->unicast.cong_avoid; - cfg_msg.unicast = &uni_cfg_msg; - break; - case IPCP_UDP: - udp_cfg_msg.ip_addr = conf->udp.ip_addr; - udp_cfg_msg.dns_addr = conf->udp.dns_addr; - udp_cfg_msg.port = conf->udp.port; - cfg_msg.udp = &udp_cfg_msg; - break; - case IPCP_LOCAL: - /* FALLTHRU */ - case IPCP_BROADCAST: - break; - case IPCP_ETH_DIX: - eth_cfg_msg.has_ethertype = true; - eth_cfg_msg.ethertype = conf->eth.ethertype; - /* FALLTHRU */ - case IPCP_ETH_LLC: - eth_cfg_msg.dev = conf->eth.dev; - cfg_msg.eth = ð_cfg_msg; - break; - default: - return -EIPCPTYPE; - } - - cfg_msg.layer_info = &layer_info_msg; - msg.conf = &cfg_msg; + msg.conf = ipcp_config_s_to_msg(conf); recv_msg = send_recv_irm_msg(&msg); + ipcp_config_msg__free_unpacked(msg.conf, NULL); if (recv_msg == NULL) return -EIRMD; @@ -175,8 +132,7 @@ int irm_connect_ipcp(pid_t pid, const char * component, qosspec_t qs) { - irm_msg_t msg = IRM_MSG__INIT; - qosspec_msg_t qs_msg = QOSSPEC_MSG__INIT; + irm_msg_t msg = IRM_MSG__INIT; irm_msg_t * recv_msg; int ret; @@ -186,10 +142,11 @@ int irm_connect_ipcp(pid_t pid, msg.comp = (char *) component; msg.has_pid = true; msg.pid = pid; - qs_msg = spec_to_msg(&qs); - msg.qosspec = &qs_msg; + msg.qosspec = qos_spec_s_to_msg(&qs); recv_msg = send_recv_irm_msg(&msg); + qosspec_msg__free_unpacked(msg.qosspec, NULL); + if (recv_msg == NULL) return -EIRMD; diff --git a/src/lib/irmd_messages.proto b/src/lib/irmd_messages.proto index 8c8c4ca8..8cf5da9e 100644 --- a/src/lib/irmd_messages.proto +++ b/src/lib/irmd_messages.proto @@ -1,7 +1,7 @@ /* * Ouroboros - Copyright (C) 2016 - 2023 * - * IRMd message + * Messages sent to IRMd * * Dimitri Staessens <dimitri@ouroboros.rocks> * Sander Vrijders <sander@ouroboros.rocks> diff --git a/src/lib/protobuf.c b/src/lib/protobuf.c new file mode 100644 index 00000000..0855305f --- /dev/null +++ b/src/lib/protobuf.c @@ -0,0 +1,438 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2023 + * + * Protobuf syntax conversion + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., http://www.fsf.org/about/contact/. + */ + +#define _DEFAULT_SOURCE + +#include <ouroboros/protobuf.h> + +#include <stdlib.h> +#include <string.h> +#include <time.h> + +layer_info_msg_t * layer_info_s_to_msg(const struct layer_info * s) +{ + layer_info_msg_t * msg; + + assert(s != NULL); + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + goto fail_malloc; + + layer_info_msg__init(msg); + + msg->layer_name = strdup(s->layer_name); + if (msg->layer_name == NULL) + goto fail_msg; + + msg->dir_hash_algo = s->dir_hash_algo; + + return msg; + + fail_msg: + layer_info_msg__free_unpacked(msg, NULL); + fail_malloc: + return NULL; +} + +struct layer_info layer_info_msg_to_s(const layer_info_msg_t * msg) +{ + struct layer_info s; + + assert(msg != NULL); + assert(strlen(msg->layer_name) <= LAYER_NAME_SIZE); + + s.dir_hash_algo = msg->dir_hash_algo; + strcpy(s.layer_name, msg->layer_name); + + return s; +} + +dt_config_msg_t * dt_config_s_to_msg(const struct dt_config * s) +{ + dt_config_msg_t * msg; + + assert(s != NULL); + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + return NULL; + + dt_config_msg__init(msg); + + msg->addr_size = s->addr_size; + msg->eid_size = s->eid_size; + msg->max_ttl = s->max_ttl; + msg->routing_type = s->routing_type; + + return msg; +} + +struct dt_config dt_config_msg_to_s(const dt_config_msg_t * msg) +{ + struct dt_config s; + + assert(msg != NULL); + + s.addr_size = msg->addr_size; + s.eid_size = msg->eid_size; + s.max_ttl = msg->max_ttl; + s.routing_type = msg->routing_type; + + return s; +} + +uni_config_msg_t * uni_config_s_to_msg(const struct uni_config * s) +{ + uni_config_msg_t * msg; + + assert(s != NULL); + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + goto fail_malloc; + + uni_config_msg__init(msg); + + msg->dt = dt_config_s_to_msg(&s->dt); + if (msg->dt == NULL) + goto fail_msg; + + msg->addr_auth_type = s->addr_auth_type; + msg->cong_avoid = s->cong_avoid; + + return msg; + + fail_msg: + uni_config_msg__free_unpacked(msg, NULL); + fail_malloc: + return NULL; +} + +struct uni_config uni_config_msg_to_s(const uni_config_msg_t * msg) +{ + struct uni_config s; + + s.dt = dt_config_msg_to_s(msg->dt); + + s.addr_auth_type = msg->addr_auth_type; + s.cong_avoid = msg->cong_avoid; + + return s; +} + +udp_config_msg_t * udp_config_s_to_msg(const struct udp_config * s) +{ + udp_config_msg_t * msg; + + assert(s != NULL); + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + return NULL; + + udp_config_msg__init(msg); + + msg->ip_addr = s->ip_addr; + msg->dns_addr = s->dns_addr; + msg->port = s->port; + + return msg; +} + +struct udp_config udp_config_msg_to_s(const udp_config_msg_t * msg) +{ + struct udp_config s; + + assert(msg != NULL); + + s.ip_addr = msg->ip_addr; + s.dns_addr = msg->dns_addr; + s.port = msg->port; + + return s; +} + +eth_config_msg_t * eth_config_s_to_msg(const struct eth_config * s) +{ + eth_config_msg_t * msg; + + assert(s != NULL); + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + goto fail_malloc; + + eth_config_msg__init(msg); + + msg->dev = strdup(s->dev); + if (msg->dev == NULL) + goto fail_msg; + + msg->ethertype = s->ethertype; + + return msg; + + fail_msg: + eth_config_msg__free_unpacked(msg, NULL); + fail_malloc: + return NULL; +} + +struct eth_config eth_config_msg_to_s(const eth_config_msg_t * msg) +{ + struct eth_config s; + + assert(msg != NULL); + assert(strlen(msg->dev) <= DEV_NAME_SIZE); + + strcpy(s.dev, msg->dev); + s.ethertype = msg->ethertype; + + return s; +} + + +ipcp_config_msg_t * ipcp_config_s_to_msg(const struct ipcp_config * s) +{ + ipcp_config_msg_t * msg; + + assert(s != NULL); + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + goto fail_malloc; + + ipcp_config_msg__init(msg); + + switch (s->type) { + case IPCP_LOCAL: + break; + case IPCP_UNICAST: + msg->unicast = uni_config_s_to_msg(&s->unicast); + if (msg->unicast == NULL) + goto fail_msg; + break; + case IPCP_BROADCAST: + break; + case IPCP_ETH_LLC: + /* FALLTHRU */ + case IPCP_ETH_DIX: + msg->eth = eth_config_s_to_msg(&s->eth); + if (msg->eth == NULL) + goto fail_msg; + break; + case IPCP_UDP: + msg->udp = udp_config_s_to_msg(&s->udp); + if (msg->udp == NULL) + goto fail_msg; + break; + default: + /* No checks here */ + break; + } + + msg->ipcp_type = s->type; + + msg->layer_info = layer_info_s_to_msg(&s->layer_info); + if (msg->layer_info == NULL) + goto fail_msg; + + return msg; + + fail_msg: + ipcp_config_msg__free_unpacked(msg, NULL); + fail_malloc: + return NULL; +} + +struct ipcp_config ipcp_config_msg_to_s(const ipcp_config_msg_t * msg) +{ + struct ipcp_config s; + + assert(msg != NULL); + + s.type = msg->ipcp_type; + + s.layer_info = layer_info_msg_to_s(msg->layer_info); + + switch(msg->ipcp_type) { + case IPCP_LOCAL: + break; + case IPCP_UNICAST: + s.unicast = uni_config_msg_to_s(msg->unicast); + break; + case IPCP_ETH_LLC: + /* FALLTHRU */ + case IPCP_ETH_DIX: + s.eth = eth_config_msg_to_s(msg->eth); + break; + case IPCP_UDP: + s.udp = udp_config_msg_to_s(msg->udp); + break; + case IPCP_BROADCAST: + break; + default: + /* No checks here */ + break; + } + + return s; +} + +qosspec_msg_t * qos_spec_s_to_msg(const struct qos_spec * s) +{ + struct qos_spec spec; + qosspec_msg_t * msg; + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + return NULL; + + qosspec_msg__init(msg); + + spec = (s == NULL ? qos_raw : *s); + + msg->delay = spec.delay; + msg->bandwidth = spec.bandwidth; + msg->availability = spec.availability; + msg->loss = spec.loss; + msg->ber = spec.ber; + msg->in_order = spec.in_order; + msg->max_gap = spec.max_gap; + msg->cypher_s = spec.cypher_s; + msg->timeout = spec.timeout; + + return msg; +} + +struct qos_spec qos_spec_msg_to_s(const qosspec_msg_t * msg) +{ + struct qos_spec s; + + assert(msg != NULL); + + s.delay = msg->delay; + s.bandwidth = msg->bandwidth; + s.availability = msg->availability; + s.loss = msg->loss; + s.ber = msg->ber; + s.in_order = msg->in_order; + s.max_gap = msg->max_gap; + s.cypher_s = msg->cypher_s; + s.timeout = msg->timeout; + + return s; +} + +enroll_req_msg_t * enroll_req_s_to_msg(void) +{ + enroll_req_msg_t * msg; + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + return NULL; + + enroll_req_msg__init(msg); + + msg->magic = 0xC0FFEE; + + return msg; +} + +int enroll_req_msg_to_s(const enroll_req_msg_t * msg) +{ + (void) msg; + + assert(msg != NULL); + + return 0; +} + +enroll_resp_msg_t * enroll_resp_s_to_msg(const struct enroll_resp * s) +{ + enroll_resp_msg_t * msg; + + assert(s != NULL); + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + goto fail_malloc; + + enroll_resp_msg__init(msg); + + msg->t_sec = s->t.tv_sec; + msg->t_nsec = s->t.tv_nsec; + msg->response = s->response; + + if (msg->response < 0) + return msg; + + msg->conf = ipcp_config_s_to_msg(&s->conf); + if (msg->conf == NULL) + goto fail_conf; + + return msg; + + fail_conf: + enroll_resp_msg__free_unpacked(msg, NULL); + fail_malloc: + return NULL; +} + +struct enroll_resp enroll_resp_msg_to_s(enroll_resp_msg_t * msg) +{ + struct enroll_resp s; + + assert (msg != NULL); + + s.response = msg->response; + if (s.response >= 0) + s.conf = ipcp_config_msg_to_s(msg->conf); + + s.t.tv_sec = msg->t_sec; + s.t.tv_nsec = msg->t_nsec; + + return s; +} + +enroll_ack_msg_t * enroll_ack_s_to_msg(int response) +{ + enroll_ack_msg_t * msg; + + msg = malloc(sizeof(*msg)); + if (msg == NULL) + return NULL; + + enroll_ack_msg__init(msg); + + msg->response = response; + + return msg; +} + +int enroll_ack_msg_to_s(const enroll_ack_msg_t * msg) +{ + assert(msg != NULL); + + return msg->response; +} diff --git a/src/lib/serdes-oep.c b/src/lib/serdes-oep.c new file mode 100644 index 00000000..cae5c598 --- /dev/null +++ b/src/lib/serdes-oep.c @@ -0,0 +1,155 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2023 + * + * Ouroboros Enrollment Protocol - serialization/deserialization + * + * 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/. + */ + +#define _POSIX_C_SOURCE 200112L + +#include <ouroboros/protobuf.h> +#include <ouroboros/serdes-oep.h> + + +ssize_t enroll_req_ser(buffer_t buf) +{ + enroll_req_msg_t * msg; + ssize_t sz; + + msg = enroll_req_s_to_msg(); + if (msg == NULL) + goto fail_msg; + + sz = enroll_req_msg__get_packed_size(msg); + if (sz < 0 || (size_t) sz > buf.len) + goto fail_pack; + + enroll_req_msg__pack(msg, buf.data); + + enroll_req_msg__free_unpacked(msg, NULL); + + return sz; + + fail_pack: + enroll_req_msg__free_unpacked(msg, NULL); + fail_msg: + return -1; +} + +int enroll_req_des(const buffer_t buf) +{ + enroll_req_msg_t * msg; + + msg = enroll_req_msg__unpack(NULL, buf.len, buf.data); + if (msg == NULL) + return -1; + + /* Nothing in request yet, if it unpacks, it's good. */ + + enroll_req_msg__free_unpacked(msg, NULL); + + return 0; +} + +ssize_t enroll_resp_ser(const struct enroll_resp * resp, + buffer_t buf) +{ + enroll_resp_msg_t * msg; + ssize_t sz; + + msg = enroll_resp_s_to_msg(resp); + if (msg == NULL) + goto fail_msg; + + sz = enroll_resp_msg__get_packed_size(msg); + if (sz < 0 || (size_t) sz > buf.len) + goto fail_pack; + + msg->t_sec = resp->t.tv_sec; + msg->t_nsec = resp->t.tv_nsec; + + enroll_resp_msg__pack(msg, buf.data); + + enroll_resp_msg__free_unpacked(msg, NULL); + + return sz; + + fail_pack: + enroll_resp_msg__free_unpacked(msg, NULL); + fail_msg: + return -1; +} + +int enroll_resp_des(struct enroll_resp * resp, + const buffer_t buf) +{ + enroll_resp_msg_t * msg; + + msg = enroll_resp_msg__unpack(NULL, buf.len, buf.data); + if (msg == NULL) + return -1; + + *resp = enroll_resp_msg_to_s(msg); + + enroll_resp_msg__free_unpacked(msg, NULL); + + return 0; +} + +ssize_t enroll_ack_ser(const int response, + buffer_t buf) +{ + enroll_ack_msg_t * msg; + ssize_t sz; + + msg = enroll_ack_s_to_msg(response); + if (msg == NULL) + goto fail_msg; + + sz = enroll_ack_msg__get_packed_size(msg); + if (sz < 0 || (size_t) sz > buf.len) + goto fail_pack; + + enroll_ack_msg__pack(msg, buf.data); + + enroll_ack_msg__free_unpacked(msg, NULL); + + return sz; + + fail_pack: + enroll_ack_msg__free_unpacked(msg, NULL); + fail_msg: + return -1; + +} + +int enroll_ack_des(int * response, + const buffer_t buf) +{ + enroll_ack_msg_t * msg; + + msg = enroll_ack_msg__unpack(NULL, buf.len, buf.data); + if (msg == NULL) + return -1; + + *response = enroll_ack_msg_to_s(msg); + + enroll_ack_msg__free_unpacked(msg, NULL); + + return 0; +}
\ No newline at end of file diff --git a/src/lib/sockets.c b/src/lib/sockets.c index c82d622f..bb594115 100644 --- a/src/lib/sockets.c +++ b/src/lib/sockets.c @@ -100,6 +100,7 @@ int server_socket_open(char * file_name) return sockfd; } +__attribute__((no_sanitize_address)) irm_msg_t * send_recv_irm_msg(irm_msg_t * msg) { int sockfd; @@ -117,18 +118,18 @@ irm_msg_t * send_recv_irm_msg(irm_msg_t * msg) return NULL; } - pthread_cleanup_push(__cleanup_close_ptr, &sockfd); - irm_msg__pack(msg, buf); + pthread_cleanup_push(__cleanup_close_ptr, &sockfd); + if (write(sockfd, buf, len) != -1) len = read(sockfd, buf, SOCK_BUF_SIZE); + pthread_cleanup_pop(true); + if (len > 0) recv_msg = irm_msg__unpack(NULL, len, buf); - pthread_cleanup_pop(true); - return recv_msg; } @@ -165,42 +166,3 @@ char * ipcp_sock_path(pid_t pid) return full_name; } - -qosspec_msg_t spec_to_msg(const qosspec_t * qs) -{ - qosspec_t spec; - qosspec_msg_t msg = QOSSPEC_MSG__INIT; - - spec = (qs == NULL ? qos_raw : *qs); - - msg.delay = spec.delay; - msg.bandwidth = spec.bandwidth; - msg.availability = spec.availability; - msg.loss = spec.loss; - msg.ber = spec.ber; - msg.in_order = spec.in_order; - msg.max_gap = spec.max_gap; - msg.cypher_s = spec.cypher_s; - msg.timeout = spec.timeout; - - return msg; -} - -qosspec_t msg_to_spec(const qosspec_msg_t * msg) -{ - qosspec_t spec; - - assert(msg); - - spec.delay = msg->delay; - spec.bandwidth = msg->bandwidth; - spec.availability = msg->availability; - spec.loss = msg->loss; - spec.ber = msg->ber; - spec.in_order = msg->in_order; - spec.max_gap = msg->max_gap; - spec.cypher_s = msg->cypher_s; - spec.timeout = msg->timeout; - - return spec; -} diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c index 2e90b82c..5d0ce680 100644 --- a/src/tools/irm/irm_ipcp_bootstrap.c +++ b/src/tools/irm/irm_ipcp_bootstrap.c @@ -193,7 +193,7 @@ int do_bootstrap_ipcp(int argc, ethertype = strtol(*(argv + 1), NULL, 0); else ethertype = strtol(*(argv + 1), NULL, 16); - if (ethertype < 0x0600 || ethertype == 0xFFFF) { + if (ethertype < 0x0600 || ethertype >= 0xFFFF) { printf("Invalid Ethertype: \"%s\".\n" "Recommended range: 0xA000-0xEFFF.\n", *(argv + 1)); @@ -332,7 +332,12 @@ int do_bootstrap_ipcp(int argc, case IPCP_ETH_LLC: if (dev == NULL) goto fail_usage; - conf.eth.dev = dev; + if (strlen(dev) > DEV_NAME_SIZE) { + printf("Device name too long.\n\n"); + goto fail_usage; + } + + strcpy(conf.eth.dev, dev); break; case IPCP_BROADCAST: /* FALLTHRU */ |