diff options
36 files changed, 2212 insertions, 465 deletions
diff --git a/doc/man/ouroboros.8 b/doc/man/ouroboros.8 index 6e051673..ebd89023 100644 --- a/doc/man/ouroboros.8 +++ b/doc/man/ouroboros.8 @@ -195,18 +195,14 @@ default: SHA3_256. .PP ip \fIip\fR specifies the local IP address to bind to .PP -[dns \fdns\fR] specifies an optional DDNS server that will be used for +[dns \fIdns\fR] specifies an optional DDNS server that will be used for the directory. .PP -[cport \fcport\fR] specifies a client UDP port that will be used for -sending packets. -.br -default: A random UDP port in the ephemeral range -.PP -[sport \fsport\fR] specifies a server UDP port that is used for +[port \fIport\fR] specifies a UDP port that is used for sending and receiving ouroboros traffic. This must be the same for the entire UDP layer. Parallel UDP layers should use different ports. This UDP port -needs to be forwarded if the server is behind a NAT. +needs to be forwarded if the server is behind a NAT and wants to +receive incoming requests. .br default: 3435 .RE diff --git a/include/ouroboros/ipcp.h b/include/ouroboros/ipcp.h index 49deeffd..c4d596b2 100644 --- a/include/ouroboros/ipcp.h +++ b/include/ouroboros/ipcp.h @@ -28,6 +28,11 @@ #include <stdbool.h> #define LAYER_NAME_SIZE 255 +#define DEV_NAME_SIZE 255 + +/* Unicast IPCP components. */ +#define DT_COMP "Data Transfer" +#define MGMT_COMP "Management" /* NOTE: The IRMd uses this order to select an IPCP for flow allocation. */ enum ipcp_type { @@ -42,25 +47,29 @@ enum ipcp_type { /* Unicast IPCP policies */ enum pol_addr_auth { - ADDR_AUTH_FLAT_RANDOM = 0 + ADDR_AUTH_FLAT_RANDOM = 0, + ADDR_AUTH_INVALID }; enum pol_routing { ROUTING_LINK_STATE = 0, ROUTING_LINK_STATE_LFA, - ROUTING_LINK_STATE_ECMP + ROUTING_LINK_STATE_ECMP, + ROUTING_INVALID }; enum pol_cong_avoid { CA_NONE = 0, - CA_MB_ECN + CA_MB_ECN, + CA_INVALID }; enum pol_dir_hash { DIR_HASH_SHA3_224, DIR_HASH_SHA3_256, DIR_HASH_SHA3_384, - DIR_HASH_SHA3_512 + DIR_HASH_SHA3_512, + DIR_HASH_INVALID }; struct dt_config { @@ -78,7 +87,7 @@ struct uni_config { }; struct eth_config { - char * dev; + char dev[DEV_NAME_SIZE + 1]; uint16_t ethertype; /* DIX only*/ }; @@ -106,4 +115,57 @@ struct ipcp_config { }; }; +/* default configurations */ +static const struct ipcp_config local_default_conf = { + .type = IPCP_LOCAL, + .layer_info = { + .dir_hash_algo = DIR_HASH_SHA3_256 + } +}; + +static const struct ipcp_config eth_dix_default_conf = { + .type = IPCP_ETH_DIX, + .layer_info = { + .dir_hash_algo = DIR_HASH_SHA3_256 + }, + .eth = { + .ethertype=0xA000, + } +}; + +static const struct ipcp_config eth_llc_default_conf = { + .type = IPCP_ETH_LLC, + .layer_info = { + .dir_hash_algo = DIR_HASH_SHA3_256 + } +}; + +static const struct ipcp_config udp_default_conf = { + .type = IPCP_UDP, + .udp = { + .port = 3435 + } +}; + +static const struct ipcp_config uni_default_conf = { + .type = IPCP_UNICAST, + .layer_info = { + .dir_hash_algo = DIR_HASH_SHA3_256 + }, + .unicast = { + .dt = { + .addr_size = 4, + .eid_size = 8, + .max_ttl = 6, + .routing_type = ROUTING_LINK_STATE + }, + .addr_auth_type = ADDR_AUTH_FLAT_RANDOM, + .cong_avoid = CA_MB_ECN + } +}; + +static const struct ipcp_config bc_default_conf = { + .type = IPCP_BROADCAST +}; + #endif /* OUROBOROS_IPCP_H */ diff --git a/include/ouroboros/irm.h b/include/ouroboros/irm.h index 7cd63866..7fcf5357 100644 --- a/include/ouroboros/irm.h +++ b/include/ouroboros/irm.h @@ -29,10 +29,6 @@ #include <sys/types.h> -/* Unicast IPCP components. */ -#define DT_COMP "Data Transfer" -#define MGMT_COMP "Management" - /* Name binding options. */ #define BIND_AUTO 0x01 @@ -42,7 +38,8 @@ /* Load balancing policy for incoming flows. */ enum pol_balance { LB_RR = 0, - LB_SPILL + LB_SPILL, + LB_INVALID }; struct ipcp_info { diff --git a/include/ouroboros/protobuf.h b/include/ouroboros/protobuf.h new file mode 100644 index 00000000..edcbe4f0 --- /dev/null +++ b/include/ouroboros/protobuf.h @@ -0,0 +1,99 @@ +/* + * 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/. + */ + +#ifndef OUROBOROS_PROTOBUF_H +#define OUROBOROS_PROTOBUF_H + +#include <ouroboros/qos.h> +#include <ouroboros/ipcp.h> +#include <ouroboros/serdes-oep.h> + +#include "ipcp_config.pb-c.h" +typedef IpcpConfigMsg ipcp_config_msg_t; +typedef LayerInfoMsg layer_info_msg_t; +typedef DtConfigMsg dt_config_msg_t; +typedef EthConfigMsg eth_config_msg_t; +typedef UdpConfigMsg udp_config_msg_t; +typedef UniConfigMsg uni_config_msg_t; + +#include "ipcpd_messages.pb-c.h" +typedef IpcpMsg ipcp_msg_t; + +#include "irmd_messages.pb-c.h" +typedef IpcpInfoMsg ipcp_info_msg_t; +typedef NameInfoMsg name_info_msg_t; + +#include "qosspec.pb-c.h" +typedef QosspecMsg qosspec_msg_t; + +#include "enroll.pb-c.h" +typedef EnrollReqMsg enroll_req_msg_t; +typedef EnrollRespMsg enroll_resp_msg_t; +typedef EnrollAckMsg enroll_ack_msg_t; + +/* IPCP configuration */ + +layer_info_msg_t * layer_info_s_to_msg(const struct layer_info * s); + +struct layer_info layer_info_msg_to_s(const layer_info_msg_t * msg); + +dt_config_msg_t * dt_config_s_to_msg(const struct dt_config * s); + +struct dt_config dt_config_msg_to_s(const dt_config_msg_t * msg); + +uni_config_msg_t * uni_config_s_to_msg(const struct uni_config * s); + +struct uni_config uni_config_msg_to_s(const uni_config_msg_t * msg); + +eth_config_msg_t * eth_config_s_to_msg(const struct eth_config * s); + +struct eth_config eth_config_msg_to_s(const eth_config_msg_t * msg); + +udp_config_msg_t * udp_config_s_to_msg(const struct udp_config * s); + +struct udp_config udp_config_msg_to_s(const udp_config_msg_t * msg); + +ipcp_config_msg_t * ipcp_config_s_to_msg(const struct ipcp_config * s); + +struct ipcp_config ipcp_config_msg_to_s(const ipcp_config_msg_t * msg); + +/* QoS */ + +qosspec_msg_t * qos_spec_s_to_msg(const struct qos_spec * s); + +struct qos_spec qos_spec_msg_to_s(const qosspec_msg_t * msg); + +/* Enrollment */ + +enroll_req_msg_t * enroll_req_s_to_msg(void); + +int enroll_req_msg_to_s(const enroll_req_msg_t * msg); + +enroll_resp_msg_t * enroll_resp_s_to_msg(const struct enroll_resp * s); + +struct enroll_resp enroll_resp_msg_to_s(enroll_resp_msg_t * msg); + +enroll_ack_msg_t * enroll_ack_s_to_msg(const int response); + +int enroll_ack_msg_to_s(const enroll_ack_msg_t * msg); + +#endif /* OUROBOROS_PROTOBUF_H */
\ No newline at end of file diff --git a/include/ouroboros/serdes-oep.h b/include/ouroboros/serdes-oep.h new file mode 100644 index 00000000..c503b31a --- /dev/null +++ b/include/ouroboros/serdes-oep.h @@ -0,0 +1,58 @@ +/* + * 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/. + */ + +#ifndef OUROBOROS_LIB_SERDES_OEP_H +#define OUROBOROS_LIB_SERDES_OEP_H + +#include <ouroboros/ipcp.h> +#include <ouroboros/utils.h> + +#include <sys/time.h> + +/* Enrollment */ + +/* no structs yet for req and ack. TODO: authentication. */ + +struct enroll_resp { + struct timespec t; + int response; + struct ipcp_config conf; +}; + + +ssize_t enroll_req_ser(buffer_t buf); + +int enroll_req_des(const buffer_t buf); + +ssize_t enroll_resp_ser(const struct enroll_resp * resp, + buffer_t buf); + +int enroll_resp_des(struct enroll_resp * resp, + buffer_t buf); + +ssize_t enroll_ack_ser(const int response, + buffer_t buf); + +int enroll_ack_des(int * response, + const buffer_t buf); + +#endif /* OUROBOROS_LIB_SERDES_OEP_H*/
\ No newline at end of file diff --git a/include/ouroboros/sockets.h.in b/include/ouroboros/sockets.h.in index b1e714f4..8d4c2f48 100644 --- a/include/ouroboros/sockets.h.in +++ b/include/ouroboros/sockets.h.in @@ -23,28 +23,10 @@ #ifndef OUROBOROS_SOCKETS_H #define OUROBOROS_SOCKETS_H -#include <ouroboros/qos.h> - #include <sys/types.h> -#include "ipcp_config.pb-c.h" -typedef IpcpConfigMsg ipcp_config_msg_t; -typedef LayerInfoMsg layer_info_msg_t; -typedef DtConfigMsg dt_config_msg_t; -typedef EthConfigMsg eth_config_msg_t; -typedef UdpConfigMsg udp_config_msg_t; -typedef UniConfigMsg uni_config_msg_t; - #include "irmd_messages.pb-c.h" typedef IrmMsg irm_msg_t; -typedef IpcpInfoMsg ipcp_info_msg_t; -typedef NameInfoMsg name_info_msg_t; - -#include "ipcpd_messages.pb-c.h" -typedef IpcpMsg ipcp_msg_t; - -#include "qosspec.pb-c.h" -typedef QosspecMsg qosspec_msg_t; #define SOCK_PATH "/var/run/ouroboros/" #define SOCK_PATH_SUFFIX ".sock" @@ -64,11 +46,6 @@ int client_socket_open(char * file_name); irm_msg_t * send_recv_irm_msg(irm_msg_t * msg); -/* qos message conversion needed in different components */ -qosspec_msg_t spec_to_msg(const qosspec_t * qs); - -qosspec_t msg_to_spec(const qosspec_msg_t * msg); - /* cleanup socket when cancelling thread */ void __cleanup_close_ptr(void * o); diff --git a/irmd.conf.in b/irmd.conf.in new file mode 100644 index 00000000..fe280a1e --- /dev/null +++ b/irmd.conf.in @@ -0,0 +1,111 @@ +### Example Ouroboros configuration file +# +# This file contains a summary of current machine configuration +# options for the O7s prototype. The IRMd will attempt to load its +# configuration file during startup from the file +# @OUROBOROS_CONFIG_DIR@@OUROBOROS_CONFIG_FILE@. +# +# At the top level, it accepts configuration of +# services via the "name" directive, and configuration of the network +# specifying different IPCPs in the system. So, the list of accepted +# top level stanza is: +# +# [name.<name of service>] add a new name to the system. +# [local.<name for IPCP>] add a new local IPCP to the system. +# [eth-llc.<name for IPCP>] add a new IPCP over Ethernet (LLC) to the system. +# [eth-dix.<name for IPCP>] add a new IPCP over Ethernet (DIX) to the system. +# [eth-udp.<name for IPCP>] add a new IPCP over UDP/IPv4 to the system. +# [broadcast.<name of IPCP>] add a new broadcast IPCP to the system. +# [unicast.<name of IPCP>] add a new unicast IPCP to the system. +# +# Options for names: +# +# A name can be created without any parameters. The following options will +# allow more useful configurations: +# prog: bind programs to this name. Whenever an instance of one of these +# programs is started, it will accept incoming flows for this name. +# args: When provided the program at the same index in the prog list will be +# automatically started if there is an incoming flow for that name. +# lb: Load-balancing option, if there are multiple processes accepting flows +# for that name, the flow will get assigned to the process according to +# the specified load-balancing algorithm. +# +# Options for IPCPs: +# +# bootstrap=<layer_name>: Immediately bootstrap this IPCP in this layer. +# enrol=<dst>: Enrol with this neigbor (broadcast and unicast only). +# conn=[<dst>]: Create mgmt and data flows with these neighbors. +# reg=[<names>]: Register these names with the IPCP. +# Bootstrap options can be set as in the examples below. +# For more details on the configuration options for each of the IPCP types, +# please refer to the Ouroboros man page. + +[name.oping] +prog=["@INSTALL_DIR@/oping"] # Defaults to []. +args=["-l"] # Defaults to disabled. Autostart server with these args. +lb="round-robin" # Defaults to spill (load-balancing options: spill, round-robin). + +[name.oecho] +lb="round-robin" # Defaults to spill (load-balancing options: spill, round-robin). +args="-l" # Defaults to disabled. Autostart server with these args. + +[name.ocbr] +prog=["@INSTALL_DIR@/ocbr"] # Defaults to []. + +[name.ovpn] +prog=["@INSTALL_DIR@/ovpn"] # Defaults to []. + +[local.local1] +bootstrap="local1" # Defaults to not set. + # BOOTSTRAP CONFIGURATION +# hash="SHA3_224" # Defaults to SHA3_256. + # NAMES KNOWN +reg=["bc1", "LAN"] # Defaults to []. + +[eth-llc.ethl] +bootstrap="ethl1" # Defaults to not set. + # BOOTSTRAP CONFIGURATION +dev="lo" +# hash="SHA3_224" # Defaults to SHA3_256. + +[eth-dix.eth1] +bootstrap="eth1" # Defaults to not set. + # BOOTSTRAP CONFIGURATION +dev="lo" +# ethertype=0xA007 # Defaults to 0xA000. +# hash="SHA3_224" # Defaults to SHA3_256. +reg=["lan1"] + +[udp.udp1] +bootstrap="udp" # Defaults to not set. + # BOOTSTRAP CONFIGURATION +ip="127.0.0.1" +# port=9000 # Defaults to 3435. +# dns="127.0.0.1" # Requires a DDNS server. Disables DDNS support if not set. + +[broadcast.bc1] +bootstrap="broadcast" # Defaults to not set. +autobind=true # Defaults to false. + +[broadcast.bc2] +enrol="bc1" +# autobind=true # Defaults to false. + +[unicast.lan1] +bootstrap="LAN" # Defaults to not set. +autobind=true # Defaults to false. + # BOOTSTRAP CONFIGURATION +# hash="SHA3_224" # Defaults to SHA3_256. +# addr_size=4 # Defaults to 4 (32-bit addresses). +# eid_size=8 # Defaults to 8 (64-bit endpoint IDs, only accepted option). +# max_ttl=60 # Defaults to 60 (max 255). +# addr-auth="flat" # Defaults to flat (currently only option). +# routing="lfa" # Defaults to link-state (options: link-state, lfa, ecmp). +# congestion="none" # Defaults to mb-ecn (options: none, mb-ecn). + # NAMES KNOWN +reg=["oping"] # Defaults to []. + +[unicast.lan2] +enrol="LAN" # Defaults to not set. +conn=["lan1"] # Defaults to []. +autobind=true # Defaults to false. diff --git a/ouroboros.service.in b/ouroboros.service.in index e6dc006e..d84b02c5 100644 --- a/ouroboros.service.in +++ b/ouroboros.service.in @@ -2,7 +2,7 @@ Description=Ouroboros IPC Resource Manager Daemon [Service] -ExecStart=@CMAKE_INSTALL_PREFIX@/sbin/irmd +ExecStart=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_SBINDIR@/irmd User=root [Install] 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 */ |