From 5c239c128c04883dbed6d66f574edf8b48d11e11 Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Sun, 16 Aug 2026 18:55:15 +0000 Subject: lib: Replace shim IPCPs with points of attachment Removes the UDP and Ethernet shim IPCPs. The unicast and broadcast IPCPs can now directly attach to a "legacy" socket. We adopt Saltzer's Point-of-Attachment terminology, also advocated in Day's "Patterns in Network Architecture". The "poa" component manages these PoA's with one management thread, one link monitoring thread and one thread per attached point. For Ethernet PoA's the irm connect and enroll can resolve the destination IPCP or Layer name with a broadcast name query over the attached PoAs (first reply wins). UDP PoA's require a destination IP address or FQDN. attach to a local endpoint (required both server and client side): irm ipcp poa attach name a udp 10.0.0.1 irm ipcp poa attach name a udp 10.0.0.1:3435 irm ipcp poa attach name a udp [::1]:3435 irm ipcp poa attach name a eth dev eth0 irm ipcp poa attach name a eth dev eth0 ethertype 0xA000 release a PoA (refused while it carries a flow): irm ipcp poa detach name a udp 10.0.0.1:3435 irm ipcp poa detach name a eth eth0 list an IPCP's PoAs: irm ipcp poa list name a connect to a peer, by name or at an address: irm ipcp connect name b dst a irm ipcp connect name b dst a eth irm ipcp connect name b dst a eth dev eth0 irm ipcp connect name b dst a udp 10.0.0.1:3435 irm ipcp connect name b dst a udp peer.example.com:3435 disconnect by peer name, no address: irm ipcp disconnect name b dst a irm ipcp disconnect name b dst a component mgmt enroll has the same shape as connect: irm ipcp enroll name b layer lr autobind irm ipcp enroll name b layer lr autobind eth dev eth0 irm ipcp enroll name b layer lr autobind udp 10.0.0.1:3435 the IRMd config file attaches PoAs and names peers the same way: udp = [ "10.0.0.1", "10.0.0.1:3436" ] eth = [ "eth0", {dev="eth1", ethertype=0xA007} ] enrol={dst="LAN", eth={dev="eth0"}} conn=[{dst="lan3", eth={}}, {dst="lan4", udp="10.0.0.1:3435"}] Signed-off-by: Dimitri Staessens Signed-off-by: Sander Vrijders --- src/irmd/config.h.in | 6 +- src/irmd/configfile.c | 553 +++++++++++++++++++++++++++----------- src/irmd/ipcp.c | 129 ++++++++- src/irmd/ipcp.h | 71 ++--- src/irmd/irmd.h | 53 ++-- src/irmd/main.c | 610 +++++++++++++++++++++++++++++++++++++++--- src/irmd/oap.h | 29 +- src/irmd/oap/cli.c | 38 +-- src/irmd/oap/tests/common.c | 19 +- src/irmd/reg/flow.c | 3 + src/irmd/reg/flow.h | 2 + src/irmd/reg/name.c | 1 - src/irmd/reg/reg.c | 73 ++++- src/irmd/reg/reg.h | 251 ++++++++--------- src/irmd/reg/tests/reg_test.c | 2 +- 15 files changed, 1423 insertions(+), 417 deletions(-) (limited to 'src/irmd') diff --git a/src/irmd/config.h.in b/src/irmd/config.h.in index 53f80ca4..2440e180 100644 --- a/src/irmd/config.h.in +++ b/src/irmd/config.h.in @@ -21,10 +21,6 @@ */ -#define IPCP_UDP4_EXEC "@IPCP_UDP4_TARGET@" -#define IPCP_UDP6_EXEC "@IPCP_UDP6_TARGET@" -#define IPCP_ETH_LLC_EXEC "@IPCP_ETH_LLC_TARGET@" -#define IPCP_ETH_DIX_EXEC "@IPCP_ETH_DIX_TARGET@" #define IPCP_UNICAST_EXEC "@IPCP_UNICAST_TARGET@" #define IPCP_BROADCAST_EXEC "@IPCP_BROADCAST_TARGET@" #define IPCP_LOCAL_EXEC "@IPCP_LOCAL_TARGET@" @@ -75,6 +71,8 @@ #define OUROBOROS_CLI_CRT_DIR "@OUROBOROS_CLI_CRT_DIR@" #define OUROBOROS_CHAIN_DIR "@OUROBOROS_UNTRUSTED_DIR@" +/* Endpoint peers are keyed on their address, not on a service name. */ + #define IRMD_PKILL_TIMEOUT @IRMD_PKILL_TIMEOUT@ #cmakedefine DISABLE_DIRECT_IPC diff --git a/src/irmd/configfile.c b/src/irmd/configfile.c index e2e1e554..de02242f 100644 --- a/src/irmd/configfile.c +++ b/src/irmd/configfile.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -92,171 +93,173 @@ static int toml_local(toml_table_t * table, 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; - } +/* Defined with the peer helpers below; shared grammar for both paths. */ +static int toml_udp_str(const char * str, + char * host, + int * port); - if (strlen(dev.u.s) > DEV_NAME_SIZE) { - log_err("Device name too long: %s", dev.u.s); - free(dev.u.s); +/* Attach the PoAs an IPCP is given; one call per PoA. */ +static int poa_eth_set(struct poa_spec * poa, + const char * dev, + uint16_t ethertype) +{ + if (strlen(dev) > DEV_NAME_SIZE) { + log_err("Invalid device name %s.", dev); return -1; } - strcpy(conf->dev, dev.u.s); - free(dev.u.s); + memset(poa, 0, sizeof(*poa)); + + poa->type = POA_ETH; + poa->eth.ethertype = ethertype; + + strcpy(poa->eth.dev, dev); return 0; } -static int toml_eth_llc(toml_table_t * table, - struct ipcp_config * conf) +static int toml_poa_eth(toml_table_t * tbl, + struct poa_spec * poa) { - *conf = eth_llc_default_conf; - - if (toml_hash(table, &conf->layer_info) < 0) - return -1; - - return toml_eth_dev(table, &conf->eth); -} + toml_datum_t dev; + toml_datum_t et; + uint16_t ethertype = POA_ETHERTYPE; + int ret = -1; + dev = toml_string_in(tbl, "dev"); + if (!dev.ok) { + log_err("An eth PoA needs a device."); + goto fail; + } -static int toml_ethertype(toml_table_t * table, - struct eth_config * conf) -{ - toml_datum_t ethertype; + et = toml_int_in(tbl, "ethertype"); + if (et.ok) { + if (et.u.i < 0 || et.u.i > 0xFFFF) { + log_err("Invalid ethertype."); + goto fail; + } - ethertype = toml_int_in(table, "ethertype"); - if (ethertype.ok) - conf->ethertype = ethertype.u.i; + ethertype = et.u.i; + } - if (conf->ethertype < 0x0600 || conf->ethertype == 0xFFFF) - return -1; + ret = poa_eth_set(poa, dev.u.s, ethertype); + fail: + if (dev.ok) + free(dev.u.s); - return 0; + return ret; } -static int toml_eth_dix(toml_table_t * table, - struct ipcp_config * conf) +/* A PoA is bound locally: only literal addresses are accepted here. */ +static int toml_poa_udp(const char * str, + struct poa_spec * poa) { - *conf = eth_dix_default_conf; + char host[POA_HOST_STRLEN + 1]; + int port; - if (toml_hash(table, &conf->layer_info) < 0) + if (toml_udp_str(str, host, &port) < 0) return -1; - if (toml_eth_dev(table, &conf->eth) < 0) - return -1; + memset(poa, 0, sizeof(*poa)); - if (toml_ethertype(table, &conf->eth) < 0) { - log_err("Ethertype not in valid range."); - return -1; + if (inet_pton(AF_INET, host, &poa->udp4.ip_addr.s_addr) == 1) { + poa->type = POA_UDP4; + poa->udp4.port = port; + return 0; } - return 0; -} - -static int toml_udp4(toml_table_t * table, - struct ipcp_config * conf) -{ - struct udp4_config * udp4; - toml_datum_t ip; - toml_datum_t port; - toml_datum_t dns; - - *conf = udp4_default_conf; - udp4 = &conf->udp4; - - ip = toml_string_in(table, "ip"); - if (!ip.ok) { - log_err("No IP address specified!"); - goto fail_ip; + if (inet_pton(AF_INET6, host, &poa->udp6.ip_addr) == 1) { + poa->type = POA_UDP6; + poa->udp6.port = port; + return 0; } - if (inet_pton (AF_INET, ip.u.s, &udp4->ip_addr.s_addr) != 1) { - log_err("Failed to parse IPv4 address %s.", ip.u.s); - goto fail_addr; - } + log_err("Invalid IP address %s.", host); - port = toml_int_in(table, "port"); - if (port.ok) - udp4->port = port.u.i; + return -1; +} - dns = toml_string_in(table, "dns"); - if (dns.ok) { - if (inet_pton(AF_INET, dns.u.s, &udp4->dns_addr.s_addr) < 0) { - log_err("Failed to parse DNS address %s.", ip.u.s); - goto fail_dns; +/* Attaches every PoA in the "udp" or "eth" array; string or table. */ +static int toml_poa_array(toml_table_t * table, + pid_t pid, + const char * key) +{ + struct poa_spec poa; + toml_array_t * arr; + int n; + int i; + bool is_eth; + + arr = toml_array_in(table, key); + if (arr == NULL) { + /* A table here would otherwise attach nothing, silently. */ + if (toml_table_in(table, key) != NULL) { + log_err("A %s PoA is an array: %s = [...] " + "or [[%s]].", key, key, key); + return -1; } - free(dns.u.s); + return 0; } - free(ip.u.s); + is_eth = strcmp(key, "eth") == 0; - return 0; + n = toml_array_nelem(arr); - fail_dns: - free(dns.u.s); - fail_addr: - free(ip.u.s); - fail_ip: - return -1; -} + for (i = 0; i < n; i++) { + toml_datum_t s; + int ret; -static int toml_udp6(toml_table_t * table, - struct ipcp_config * conf) -{ - struct in6_addr ip6; - struct in6_addr dns6; - toml_datum_t ip; - toml_datum_t port; - toml_datum_t dns; - - *conf = udp6_default_conf; - ip6 = conf->udp6.ip_addr; - dns6 = conf->udp6.dns_addr; - - ip = toml_string_in(table, "ip"); - if (!ip.ok) { - log_err("No IP address specified!"); - goto fail_ip; - } + s = toml_string_at(arr, i); + if (s.ok) { + if (is_eth) + ret = poa_eth_set(&poa, s.u.s, + POA_ETHERTYPE); + else + ret = toml_poa_udp(s.u.s, &poa); - if (inet_pton (AF_INET6, ip.u.s, &ip6.s6_addr) != 1) { - log_err("Failed to parse IPv4 address %s.", ip.u.s); - goto fail_addr; - } + free(s.u.s); + } else { + toml_table_t * d = toml_table_at(arr, i); - port = toml_int_in(table, "port"); - if (port.ok) - conf->udp6.port = port.u.i; + if (d == NULL) { + log_err("Invalid %s PoA entry.", key); + return -1; + } + + if (is_eth) { + ret = toml_poa_eth(d, &poa); + } else { + toml_datum_t addr = toml_string_in(d, "addr"); + + if (!addr.ok) { + log_err("No addr for udp PoA."); + return -1; + } - dns = toml_string_in(table, "dns"); - if (dns.ok) { - if (inet_pton(AF_INET6, dns.u.s, &dns6.s6_addr) < 0) { - log_err("Failed to parse DNS address %s.", ip.u.s); - goto fail_dns; + ret = toml_poa_udp(addr.u.s, &poa); + free(addr.u.s); + } } - free(dns.u.s); - } + if (ret < 0) + return -1; - free(ip.u.s); + if (attach_ipcp(pid, &poa, true) < 0) + return -1; + } return 0; +} - fail_dns: - free(dns.u.s); - fail_addr: - free(ip.u.s); - fail_ip: - return -1; +static int toml_attach(toml_table_t * table, + pid_t pid) +{ + if (toml_poa_array(table, pid, "udp") < 0) + return -1; + + return toml_poa_array(table, pid, "eth"); } static int toml_broadcast(toml_table_t * table, @@ -265,15 +268,13 @@ static int toml_broadcast(toml_table_t * table, (void) table; (void) conf; - /* Nothing to do here. */ - return 0; } #define BETWEEN(a, b, c) ((a) >= (b) && (a) <= (c)) #define DHT(conf, x) (conf)->dht.params.x static int toml_dir(toml_table_t * table, - struct dir_config * conf) + struct dir_config * conf) { toml_datum_t dir; toml_datum_t alpha; @@ -594,6 +595,207 @@ static int toml_register(toml_table_t * table, return ret; } +/* Fills in a peer's eth PoA; dst MAC stays zero, the resolve marker. */ +static int toml_peer_eth(toml_table_t * tbl, + struct poa_addr * addr) +{ + toml_datum_t dev; + toml_datum_t et; + int ret = -1; + + dev = toml_string_in(tbl, "dev"); + + memset(addr, 0, sizeof(*addr)); + + addr->type = POA_ETH; + addr->eth.src.ethertype = POA_ETHERTYPE; + addr->eth.dst.ethertype = POA_ETHERTYPE; + + et = toml_int_in(tbl, "ethertype"); + if (et.ok) { + if (et.u.i < 0 || et.u.i > 0xFFFF) { + log_err("Invalid ethertype."); + goto fail; + } + + addr->eth.src.ethertype = et.u.i; + addr->eth.dst.ethertype = et.u.i; + } + + if (dev.ok) { + if (strlen(dev.u.s) > DEV_NAME_SIZE) { + log_err("Invalid device name %s.", dev.u.s); + goto fail; + } + + strcpy(addr->eth.src.dev, dev.u.s); + } + + ret = 0; + fail: + if (dev.ok) + free(dev.u.s); + + return ret; +} + +/* Same grammar as the CLI's udp keyword; see irm_utils.c parse_udp_str. */ +static int toml_udp_str(const char * str, + char * host, + int * port) +{ + struct in6_addr v6; + char buf[POA_HOST_STRLEN + 1]; + char * p; + char * end; + long n; + + *port = POA_UDP_PORT; + + if (strlen(str) > POA_HOST_STRLEN) + goto fail; + + strcpy(buf, str); + + if (buf[0] == '[') { + p = strchr(buf, ']'); + if (p == NULL) + goto fail; + + *p++ = '\0'; + + strcpy(host, buf + 1); + + if (*p == '\0') + return 0; + + if (*p != ':') + goto fail; + + ++p; + } else if (inet_pton(AF_INET6, buf, &v6) == 1) { + strcpy(host, buf); + return 0; + } else { + p = strrchr(buf, ':'); + if (p == NULL) { + strcpy(host, buf); + return 0; + } + + *p++ = '\0'; + + strcpy(host, buf); + } + + n = strtol(p, &end, 10); + if (*p == '\0' || *end != '\0' || n < 1 || n > 65535) + goto fail; + + *port = (int) n; + + return 0; + fail: + log_err("Invalid UDP address: %s.", str); + return -1; +} + +/* Fills in a peer's udp PoA; an unresolved name is left for the IRMd. */ +static int toml_peer_udp(const char * str, + struct poa_addr * addr) +{ + char host[POA_HOST_STRLEN + 1]; + int port; + + if (toml_udp_str(str, host, &port) < 0) + return -1; + + memset(addr, 0, sizeof(*addr)); + + if (inet_pton(AF_INET, host, &addr->udp4.ip_addr) == 1) { + addr->type = POA_UDP4; + addr->udp4.port = port; + return 0; + } + + if (inet_pton(AF_INET6, host, &addr->udp6.ip_addr) == 1) { + addr->type = POA_UDP6; + addr->udp6.port = port; + return 0; + } + + addr->type = POA_UDP; + addr->udp4.port = port; + + strcpy(addr->hostname, host); + + return 0; +} + +/* + * An entry is a name, or a table naming a PoA to reach it over. + * On entry, *paddr already points at the caller's struct poa_addr to + * fill in. Set to NULL wherever there is no PoA to dial: a bare + * dst-only table (recursive lookup) or any parse failure. + */ +static int toml_peer(toml_table_t * tbl, + char * dst, + struct poa_addr ** paddr) +{ + struct poa_addr * addr = *paddr; + toml_table_t * eth; + toml_datum_t name; + toml_datum_t udp; + int ret = -1; + + name = toml_string_in(tbl, "dst"); + if (!name.ok) { + log_err("PoA table entry has no dst."); + + *paddr = NULL; + return -1; + } + + if (strlen(name.u.s) > LAYER_NAME_SIZE) { + log_err("Destination name too long: %s.", name.u.s); + free(name.u.s); + + *paddr = NULL; + return -1; + } + + strcpy(dst, name.u.s); + free(name.u.s); + + eth = toml_table_in(tbl, "eth"); + udp = toml_string_in(tbl, "udp"); + if (eth != NULL && udp.ok) { + log_err("A PoA is eth or udp, not both."); + + *paddr = NULL; + goto fail; + } + + if (eth == NULL && !udp.ok) { + *paddr = NULL; + ret = 0; + goto fail; + } + + if (eth != NULL) + ret = toml_peer_eth(eth, addr); + else + ret = toml_peer_udp(udp.u.s, addr); + + if (ret < 0) + *paddr = NULL; + fail: + if (udp.ok) + free(udp.u.s); + + return ret; +} + static int toml_connect(toml_table_t * table, pid_t pid) { @@ -605,21 +807,40 @@ static int toml_connect(toml_table_t * table, if (conn == NULL) return 0; - for (i=0; ret == 0; i++) { - toml_datum_t dst; - qosspec_t qs = qos_raw; + for (i = 0; ret == 0; i++) { + toml_datum_t dst; + toml_table_t * tbl; + struct poa_addr addr; + struct poa_addr * paddr = &addr; + char buf[LAYER_NAME_SIZE + 1]; + const char * d; + qosspec_t qs = qos_raw; dst = toml_string_at(conn, i); - if (!dst.ok) - break; + if (dst.ok) { + d = dst.u.s; + paddr = NULL; + } else { + tbl = toml_table_at(conn, i); + if (tbl == NULL) + break; + + ret = toml_peer(tbl, buf, &paddr); + if (ret < 0) + break; + + d = buf; + } + + log_dbg("Connecting %d to %s", pid, d); - log_dbg("Connecting %d to %s", pid, dst.u.s); + ret = connect_ipcp_resolve(pid, d, MGMT_COMP, qs, paddr); - ret = connect_ipcp(pid, dst.u.s, MGMT_COMP, qs); if (ret == 0) - ret = connect_ipcp(pid, dst.u.s, DT_COMP, qs); + ret = connect_ipcp_resolve(pid, d, DT_COMP, qs, paddr); - free(dst.u.s); + if (dst.ok) + free(dst.u.s); } return ret; @@ -629,9 +850,11 @@ static int toml_ipcp(toml_table_t * table, struct ipcp_info * info, struct ipcp_config * conf) { - toml_datum_t bootstrap; - toml_datum_t enrol; - int ret; + toml_datum_t bootstrap; + toml_datum_t enrol; + toml_table_t * enrol_tbl; + bool have_enrol; + int ret; log_dbg("Found IPCP %s in configuration file.", info->name); @@ -643,21 +866,49 @@ static int toml_ipcp(toml_table_t * table, bootstrap = toml_string_in(table, "bootstrap"); enrol = toml_string_in(table, "enrol"); - if (bootstrap.ok && enrol.ok) { + enrol_tbl = enrol.ok ? NULL : toml_table_in(table, "enrol"); + + have_enrol = enrol.ok || enrol_tbl != NULL; + if (bootstrap.ok && have_enrol) { log_err("Ignoring bootstrap for IPCP %s.", info->name); free(bootstrap.u.s); bootstrap.ok = false; } - if (!bootstrap.ok && !enrol.ok) { + if (!bootstrap.ok && !have_enrol) { log_dbg("Nothing more to do for %s.", info->name); return 0; } - if (enrol.ok) { + /* Endpoints come first: enrolment reaches the peer over one. */ + if (toml_attach(table, info->pid) < 0) { + log_err("Failed to attach PoAs for %s.", info->name); + return -1; + } + + if (have_enrol) { struct layer_info layer; - ret = enroll_ipcp(info->pid, enrol.u.s); - free(enrol.u.s); + struct poa_addr addr; + struct poa_addr * paddr = &addr; + char buf[LAYER_NAME_SIZE + 1]; + const char * dst; + + if (enrol.ok) { + dst = enrol.u.s; + paddr = NULL; + } else { + if (toml_peer(enrol_tbl, buf, &paddr) < 0) { + log_err("Invalid enrol table for %s.", + info->name); + return -1; + } + dst = buf; + } + + ret = enroll_ipcp_resolve(info->pid, dst, paddr); + + if (enrol.ok) + free(enrol.u.s); if (ret < 0) { log_err("Failed to enrol %s.", info->name); return -1; @@ -694,18 +945,6 @@ static int toml_ipcp(toml_table_t * table, 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_UDP4: - ret = toml_udp4(table, conf); - break; - case IPCP_UDP6: - ret = toml_udp6(table, conf); - break; case IPCP_BROADCAST: ret = toml_broadcast(table, conf); break; @@ -1031,14 +1270,6 @@ static int toml_toplevel(toml_table_t * table, return toml_name_list(subtable); else if (strcmp(key, "local") == 0) return toml_ipcp_list(subtable, IPCP_LOCAL); - else if (strcmp(key, "eth-dix") == 0) - return toml_ipcp_list(subtable, IPCP_ETH_DIX); - else if (strcmp(key, "eth-llc") == 0) - return toml_ipcp_list(subtable, IPCP_ETH_LLC); - else if (strcmp(key, "udp4") == 0) - return toml_ipcp_list(subtable, IPCP_UDP4); - else if (strcmp(key, "udp6") == 0) - return toml_ipcp_list(subtable, IPCP_UDP6); else if (strcmp(key, "broadcast") == 0) return toml_ipcp_list(subtable, IPCP_BROADCAST); else if (strcmp(key, "unicast") == 0) diff --git a/src/irmd/ipcp.c b/src/irmd/ipcp.c index 7eccfc80..cd662221 100644 --- a/src/irmd/ipcp.c +++ b/src/irmd/ipcp.c @@ -34,6 +34,7 @@ #include #include "ipcp.h" +#include "reg/reg.h" #include #include @@ -72,6 +73,10 @@ static char * str_ipcp_cmd(int code) return "alloc_resp"; case IPCP_MSG_CODE__IPCP_FLOW_DEALLOC: return "dealloc"; + case IPCP_MSG_CODE__IPCP_FLOW_UPDATE: + return "flow_update"; + case IPCP_MSG_CODE__IPCP_REPLY: + return "reply"; default: assert(false); return "unknown"; @@ -196,7 +201,9 @@ int ipcp_bootstrap(pid_t pid, 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; @@ -225,9 +232,88 @@ int ipcp_bootstrap(pid_t pid, return ret; } -int ipcp_enroll(pid_t pid, - const char * dst, - struct layer_info * info) +ssize_t ipcp_list_poas(pid_t pid, + struct poa_spec ** eps) +{ + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + size_t nr; + size_t i; + + if (eps == NULL) + return -EINVAL; + + *eps = NULL; + + msg.code = IPCP_MSG_CODE__IPCP_LIST_POAS; + + recv_msg = send_recv_ipcp_msg(pid, &msg); + if (recv_msg == NULL) + return -EIPCP; + + nr = recv_msg->n_poas; + if (nr == 0) { + ipcp_msg__free_unpacked(recv_msg, NULL); + return 0; + } + + *eps = malloc(nr * sizeof(**eps)); + if (*eps == NULL) { + ipcp_msg__free_unpacked(recv_msg, NULL); + return -ENOMEM; + } + + for (i = 0; i < nr; i++) + (*eps)[i] = poa_spec_msg_to_s(recv_msg->poas[i]); + + ipcp_msg__free_unpacked(recv_msg, NULL); + + return (ssize_t) nr; +} + +int ipcp_attach(pid_t pid, + const struct poa_spec * poa, + bool attach) +{ + ipcp_msg_t msg = IPCP_MSG__INIT; + ipcp_msg_t * recv_msg; + int ret; + + if (poa == NULL) + return -EINVAL; + + if (attach) + msg.code = IPCP_MSG_CODE__IPCP_ATTACH; + else + msg.code = IPCP_MSG_CODE__IPCP_DETACH; + + msg.poa = poa_spec_s_to_msg(poa); + if (msg.poa == NULL) + return -EINVAL; + + recv_msg = send_recv_ipcp_msg(pid, &msg); + + poa_spec_msg__free_unpacked(msg.poa, NULL); + + if (recv_msg == NULL) + return -EIPCP; + + if (!recv_msg->has_result) { + ipcp_msg__free_unpacked(recv_msg, NULL); + return -EIPCP; + } + + ret = recv_msg->result; + + ipcp_msg__free_unpacked(recv_msg, NULL); + + return ret; +} + +int ipcp_enroll(pid_t pid, + const char * dst, + const struct poa_addr * addr, + struct layer_info * info) { ipcp_msg_t msg = IPCP_MSG__INIT; ipcp_msg_t * recv_msg; @@ -239,7 +325,16 @@ int ipcp_enroll(pid_t pid, msg.code = IPCP_MSG_CODE__IPCP_ENROLL; msg.dst = (char *) dst; + if (addr != NULL) { + msg.peer = poa_addr_s_to_msg(addr); + if (msg.peer == NULL) + return -ENOMEM; + } + recv_msg = send_recv_ipcp_msg(pid, &msg); + + if (msg.peer != NULL) + poa_addr_msg__free_unpacked(msg.peer, NULL); if (recv_msg == NULL) return -EIPCP; @@ -267,10 +362,11 @@ int ipcp_enroll(pid_t pid, return 0; } -int ipcp_connect(pid_t pid, - const char * dst, - const char * component, - qosspec_t qs) +int ipcp_connect(pid_t pid, + const char * dst, + const char * component, + qosspec_t qs, + const struct poa_addr * addr) { ipcp_msg_t msg = IPCP_MSG__INIT; ipcp_msg_t * recv_msg; @@ -283,8 +379,21 @@ int ipcp_connect(pid_t pid, msg.pid = pid; msg.qosspec = qos_spec_s_to_msg(&qs); + if (addr != NULL) { + msg.peer = poa_addr_s_to_msg(addr); + if (msg.peer == NULL) { + free(msg.qosspec); + return -ENOMEM; + } + } + recv_msg = send_recv_ipcp_msg(pid, &msg); + + if (msg.peer != NULL) + poa_addr_msg__free_unpacked(msg.peer, NULL); + free(msg.qosspec); + if (recv_msg == NULL) return -EIPCP; @@ -457,6 +566,8 @@ int ipcp_flow_update(const struct flow_info * flow, msg.has_pk = true; msg.pk.data = data.data; msg.pk.len = data.len; + msg.has_is_poa = true; + msg.is_poa = reg_flow_is_poa(flow->id); recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg); if (recv_msg == NULL) { @@ -538,6 +649,8 @@ int ipcp_flow_alloc_resp(const struct flow_info * flow, msg.has_pk = response == 0; msg.pk.data = data.data; msg.pk.len = data.len; + msg.has_is_poa = true; + msg.is_poa = reg_flow_is_poa(flow->id); recv_msg = send_recv_ipcp_msg(flow->n_1_pid, &msg); if (recv_msg == NULL) @@ -567,6 +680,8 @@ int ipcp_flow_dealloc(pid_t pid, msg.flow_id = flow_id; msg.has_timeo_sec = true; msg.timeo_sec = timeo; + msg.has_is_poa = true; + msg.is_poa = reg_flow_is_poa(flow_id); recv_msg = send_recv_ipcp_msg(pid, &msg); if (recv_msg == NULL) diff --git a/src/irmd/ipcp.h b/src/irmd/ipcp.h index 8d06623c..1f257e7d 100644 --- a/src/irmd/ipcp.h +++ b/src/irmd/ipcp.h @@ -27,48 +27,57 @@ #ifndef OUROBOROS_IRMD_IPCP_H #define OUROBOROS_IRMD_IPCP_H -int ipcp_enroll(pid_t pid, - const char * dst, - struct layer_info * info); +int ipcp_enroll(pid_t pid, + const char * dst, + const struct poa_addr * addr, + struct layer_info * info); -int ipcp_bootstrap(pid_t pid, - struct ipcp_config * conf, - struct layer_info * info); +int ipcp_attach(pid_t pid, + const struct poa_spec * poa, + bool attach); -int ipcp_connect(pid_t pid, - const char * dst, - const char * component, - qosspec_t qs); +ssize_t ipcp_list_poas(pid_t pid, + struct poa_spec ** eps); -int ipcp_disconnect(pid_t pid, - const char * dst, - const char * component); +int ipcp_bootstrap(pid_t pid, + struct ipcp_config * conf, + struct layer_info * info); -int ipcp_reg(pid_t pid, - const buffer_t hash); +int ipcp_connect(pid_t pid, + const char * dst, + const char * component, + qosspec_t qs, + const struct poa_addr * addr); -int ipcp_unreg(pid_t pid, +int ipcp_disconnect(pid_t pid, + const char * dst, + const char * component); + +int ipcp_reg(pid_t pid, const buffer_t hash); -int ipcp_query(pid_t pid, - const buffer_t dst); +int ipcp_unreg(pid_t pid, + const buffer_t hash); + +int ipcp_query(pid_t pid, + const buffer_t dst); -int ipcp_flow_alloc(const struct flow_info * flow, - const buffer_t hash, - const buffer_t data); +int ipcp_flow_alloc(const struct flow_info * flow, + const buffer_t hash, + const buffer_t data); -int ipcp_flow_join(const struct flow_info * flow, - const buffer_t dst); +int ipcp_flow_join(const struct flow_info * flow, + const buffer_t dst); -int ipcp_flow_alloc_resp(const struct flow_info * flow, - int response, - const buffer_t data); +int ipcp_flow_alloc_resp(const struct flow_info * flow, + int response, + const buffer_t data); -int ipcp_flow_dealloc(pid_t pid, - int flow_id, - time_t timeo); +int ipcp_flow_dealloc(pid_t pid, + int flow_id, + time_t timeo); -int ipcp_flow_update(const struct flow_info * flow, - const buffer_t data); +int ipcp_flow_update(const struct flow_info * flow, + const buffer_t data); #endif /* OUROBOROS_IRMD_IPCP_H */ diff --git a/src/irmd/irmd.h b/src/irmd/irmd.h index f88378ad..9d42e248 100644 --- a/src/irmd/irmd.h +++ b/src/irmd/irmd.h @@ -26,29 +26,48 @@ #include #include -int create_ipcp(struct ipcp_info * info); +int create_ipcp(struct ipcp_info * info); -int bootstrap_ipcp(pid_t pid, - struct ipcp_config * conf); +int bootstrap_ipcp(pid_t pid, + struct ipcp_config * conf); -int enroll_ipcp(pid_t pid, - const char * dst); +int enroll_ipcp(pid_t pid, + const char * dst, + const struct poa_addr * addr); -int connect_ipcp(pid_t pid, - const char * dst, - const char * component, - qosspec_t qs); +int enroll_ipcp_resolve(pid_t pid, + const char * dst, + struct poa_addr * addr); -int name_create(struct name_info * info); +int attach_ipcp(pid_t pid, + const struct poa_spec * poa, + bool attach); -int name_reg(const char * name, - pid_t pid); +ssize_t list_poas(pid_t pid, + struct poa_spec ** eps); -int bind_process(pid_t pid, - const char * name); +int connect_ipcp(pid_t pid, + const char * dst, + const char * component, + qosspec_t qs, + const struct poa_addr * addr); -int bind_program(char ** exec, - const char * name, - uint8_t flags); +int connect_ipcp_resolve(pid_t pid, + const char * dst, + const char * component, + qosspec_t qs, + struct poa_addr * addr); + +int name_create(struct name_info * info); + +int name_reg(const char * name, + pid_t pid); + +int bind_process(pid_t pid, + const char * name); + +int bind_program(char ** exec, + const char * name, + uint8_t flags); #endif /* OUROBOROS_IRMD_H*/ diff --git a/src/irmd/main.c b/src/irmd/main.c index 19be4ab9..e587a552 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -61,6 +61,7 @@ #include #include +#include #include #include #include @@ -225,18 +226,6 @@ static pid_t spawn_ipcp(struct ipcp_info * info) case IPCP_BROADCAST: exec_name = IPCP_BROADCAST_EXEC; break; - case IPCP_UDP4: - exec_name = IPCP_UDP4_EXEC; - break; - case IPCP_UDP6: - exec_name = IPCP_UDP6_EXEC; - break; - case IPCP_ETH_LLC: - exec_name = IPCP_ETH_LLC_EXEC; - break; - case IPCP_ETH_DIX: - exec_name = IPCP_ETH_DIX_EXEC; - break; case IPCP_LOCAL: exec_name = IPCP_LOCAL_EXEC; break; @@ -367,9 +356,6 @@ int bootstrap_ipcp(pid_t pid, goto fail; } - if (conf->type == IPCP_UDP4 || conf->type == IPCP_UDP6) - conf->layer_info.dir_hash_algo = (enum pol_dir_hash) HASH_MD5; - if (ipcp_bootstrap(pid, conf, &layer)) { log_err("Could not bootstrap IPCP."); goto fail; @@ -389,8 +375,55 @@ int bootstrap_ipcp(pid_t pid, return -1; } -int enroll_ipcp(pid_t pid, - const char * dst) +ssize_t list_poas(pid_t pid, + struct poa_spec ** eps) +{ + struct ipcp_info info; + + info.pid = pid; + if (reg_get_ipcp(&info, NULL) < 0) { + log_err("Could not find IPCP %d.", pid); + return -1; + } + + if (info.type != IPCP_UNICAST && info.type != IPCP_BROADCAST) + return 0; /* nothing it could be attached to */ + + return ipcp_list_poas(pid, eps); +} + +/* Only the types that can carry a PoA may take one. */ +int attach_ipcp(pid_t pid, + const struct poa_spec * poa, + bool attach) +{ + struct ipcp_info info; + + info.pid = pid; + if (reg_get_ipcp(&info, NULL) < 0) { + log_err("Could not find IPCP %d.", pid); + return -1; + } + + if (info.type != IPCP_UNICAST && info.type != IPCP_BROADCAST) { + log_err("IPCP %d does not support PoAs.", pid); + return -1; + } + + if (ipcp_attach(pid, poa, attach) < 0) { + log_err("Could not %s IPCP %d.", + attach ? "attach" : "detach", pid); + return -1; + } + + log_info("%s IPCP %d.", attach ? "Attached" : "Detached", pid); + + return 0; +} + +int enroll_ipcp(pid_t pid, + const char * dst, + const struct poa_addr * addr) { struct layer_info layer; struct ipcp_info info; @@ -402,7 +435,7 @@ int enroll_ipcp(pid_t pid, goto fail; } - if (ipcp_enroll(pid, dst, &layer) < 0) { + if (ipcp_enroll(pid, dst, addr, &layer) < 0) { log_err("Could not enroll IPCP %d.", pid); goto fail; } @@ -421,10 +454,11 @@ int enroll_ipcp(pid_t pid, return -1; } -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, + const struct poa_addr * addr) { struct ipcp_info info; @@ -442,7 +476,7 @@ int connect_ipcp(pid_t pid, log_dbg("Connecting %s to %s.", component, dst); - if (ipcp_connect(pid, dst, component, qs)) { + if (ipcp_connect(pid, dst, component, qs, addr) < 0) { log_err("Could not connect IPCP %d to %s.", pid, dst); return -EPERM; } @@ -453,6 +487,172 @@ int connect_ipcp(pid_t pid, return 0; } +/* Resolve the dial name, if any, and fill in one record. */ +static int poa_addr_resolve(struct poa_addr * addr, + struct addrinfo ** res) +{ + struct addrinfo hints; + + *res = NULL; + + if (addr == NULL) + return 0; + + if (addr->hostname[0] == '\0') + return addr->type == POA_UDP ? -EINVAL : 0; + + if (addr->type != POA_UDP) + return -EINVAL; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if (getaddrinfo(addr->hostname, NULL, &hints, res) != 0) { + log_err("Failed to resolve %s.", addr->hostname); + return -EADDRNOTAVAIL; + } + + return 0; +} + +static void poa_addr_from_ai(struct poa_addr * addr, + const struct addrinfo * ai, + uint16_t port) +{ + struct sockaddr_in * in; + struct sockaddr_in6 * in6; + + if (ai->ai_family == AF_INET) { + in = (struct sockaddr_in *) ai->ai_addr; + addr->type = POA_UDP4; + addr->udp4.ip_addr = in->sin_addr; + addr->udp4.port = port; + } else { + in6 = (struct sockaddr_in6 *) ai->ai_addr; + addr->type = POA_UDP6; + addr->udp6.ip_addr = in6->sin6_addr; + addr->udp6.port = port; + } +} + +/* Skip families without an attached PoA; keep all if none reported. */ +static void poa_families(pid_t pid, + bool * v4, + bool * v6) +{ + struct poa_spec * eps; + ssize_t n; + ssize_t i; + + eps = NULL; + + *v4 = false; + *v6 = false; + + n = list_poas(pid, &eps); + for (i = 0; i < n; i++) { + if (eps[i].type == POA_UDP4) + *v4 = true; + + if (eps[i].type == POA_UDP6) + *v6 = true; + } + + free(eps); + + if (!*v4 && !*v6) { + *v4 = true; + *v6 = true; + } +} + +/* Try each resolved record in order until an enrolment succeeds. */ +int enroll_ipcp_resolve(pid_t pid, + const char * dst, + struct poa_addr * addr) +{ + struct addrinfo * res; + struct addrinfo * ai; + uint16_t port; + bool v4; + bool v6; + int ret; + + ret = poa_addr_resolve(addr, &res); + if (ret < 0) + return ret; + + if (res == NULL) + return enroll_ipcp(pid, dst, addr); + + port = addr->udp4.port; /* POA_UDP parks it there */ + + poa_families(pid, &v4, &v6); + + ret = -EADDRNOTAVAIL; + + for (ai = res; ai != NULL; ai = ai->ai_next) { + if ((ai->ai_family == AF_INET && !v4) + || (ai->ai_family == AF_INET6 && !v6)) + continue; + + poa_addr_from_ai(addr, ai, port); + + ret = enroll_ipcp(pid, dst, addr); + if (ret == 0) + break; + } + + freeaddrinfo(res); + + return ret; +} + +/* Try each resolved record in order until a connect succeeds. */ +int connect_ipcp_resolve(pid_t pid, + const char * dst, + const char * component, + qosspec_t qs, + struct poa_addr * addr) +{ + struct addrinfo * res; + struct addrinfo * ai; + uint16_t port; + bool v4; + bool v6; + int ret; + + ret = poa_addr_resolve(addr, &res); + if (ret < 0) + return ret; + + if (res == NULL) + return connect_ipcp(pid, dst, component, qs, addr); + + port = addr->udp4.port; /* POA_UDP parks it there */ + + poa_families(pid, &v4, &v6); + + ret = -EADDRNOTAVAIL; + + for (ai = res; ai != NULL; ai = ai->ai_next) { + if ((ai->ai_family == AF_INET && !v4) + || (ai->ai_family == AF_INET6 && !v6)) + continue; + + poa_addr_from_ai(addr, ai, port); + + ret = connect_ipcp(pid, dst, component, qs, addr); + if (ret == 0) + break; + } + + freeaddrinfo(res); + + return ret; +} + static int disconnect_ipcp(pid_t pid, const char * dst, const char * component) @@ -882,6 +1082,22 @@ static void __cleanup_flow(void * flow) reg_destroy_flow(((struct flow_info *) flow)->id); } +/* + * A PoA flow is secured as the IPCP that owns it: trust is in the + * peer itself. Without a security config for that name the flow + * stays in the clear. + */ +static void poa_name_info(const char * name, + struct name_info * info) +{ + if (reg_get_name_info(name, info) == 0) + return; + + memset(info, 0, sizeof(*info)); + + strcpy(info->name, name); +} + static int flow_accept(struct flow_info * flow, buffer_t * data, struct timespec * abstime, @@ -942,7 +1158,9 @@ static int flow_accept(struct flow_info * flow, goto fail_oap; } - if (reg_get_name_info(name, &info) < 0) { + if (reg_flow_is_poa(flow->id)) { + poa_name_info(name, &info); + } else if (reg_get_name_info(name, &info) < 0) { log_err("Failed to get name info for %s.", name); err = -ENAME; goto fail_oap; @@ -1262,7 +1480,7 @@ static int flow_alloc_direct(const char * dst, return -EAGAIN; } - if (oap_cli_prepare(&ctx, info, &req_hdr, *data, false) < 0) { + if (oap_cli_prepare(&ctx, info, NULL, &req_hdr, *data, false) < 0) { log_err("Failed to prepare OAP for %s.", dst); return -EBADF; } @@ -1295,7 +1513,7 @@ static int flow_alloc_direct(const char * dst, return -ETIMEDOUT; } - err = oap_cli_complete(ctx, info, resp_hdr, data, sk, NULL, NULL); + err = oap_cli_complete(ctx, resp_hdr, data, sk, NULL, NULL); if (err < 0) { log_err("OAP completion failed for %s.", dst); freebuf(resp_hdr); @@ -1378,7 +1596,7 @@ static int flow_alloc(const char * dst, goto fail_prepare; } - if (oap_cli_prepare(&ctx, &info, &req_hdr, *data, false) < 0) { + if (oap_cli_prepare(&ctx, &info, NULL, &req_hdr, *data, false) < 0) { log_err("Failed to prepare OAP request for %s.", dst); err = -EBADF; goto fail_prepare; @@ -1410,7 +1628,7 @@ static int flow_alloc(const char * dst, goto fail_peer; } - err = oap_cli_complete(ctx, &info, resp_hdr, data, sk, NULL, &peer_crt); + err = oap_cli_complete(ctx, resp_hdr, data, sk, NULL, &peer_crt); if (err < 0) { log_err("OAP completion failed for %s.", dst); goto fail_complete; @@ -1444,6 +1662,199 @@ static int flow_alloc(const char * dst, return err; } +/* Creates the flow and prepares the key exchange the IPCP will carry. */ +/* The N-1 is only known once the flow exists. */ +static int poa_alloc(struct flow_info * flow, + const char * dst, + buffer_t * data) +{ + struct ipcp_info ipcp; + struct layer_info layer; + struct name_info info; + buffer_t req_hdr = BUF_INIT; + void * ctx; + int err; + + ipcp.pid = flow->n_pid; + if (reg_get_ipcp(&ipcp, &layer) < 0) { + log_err("No IPCP with pid %d.", flow->n_pid); + + err = -EIPCP; + goto fail_flow; + } + + flow->n_1_pid = 0; + if (reg_create_flow(flow) < 0) { + log_err("Failed to create PoA flow."); + + err = -EBADF; + goto fail_flow; + } + + reg_set_name_for_flow_id(ipcp.name, flow->id); + + if (reg_flow_set_poa(flow->id) < 0) { + err = -EBADF; + goto fail_prepare; + } + + flow->uid = reg_get_proc_uid(flow->n_pid); + flow->n_1_pid = flow->n_pid; /* the IPCP is its own N-1 */ + if (reg_prepare_flow_alloc(flow) < 0) { + log_err("Failed to prepare PoA flow allocation."); + + err = -EBADF; + goto fail_prepare; + } + + poa_name_info(ipcp.name, &info); + + if (oap_cli_prepare(&ctx, &info, dst, &req_hdr, *data, false) < 0) { + log_err("Failed to prepare OAP request for %s.", ipcp.name); + + err = -EBADF; + goto fail_prepare; + } + + if (reg_flow_set_oap_ctx(flow->id, ctx) < 0) { + err = -EBADF; + goto fail_ctx; + } + + log_info("Allocating PoA flow %d for %d as %s.", + flow->id, flow->n_pid, ipcp.name); + + *data = req_hdr; + + return 0; + + fail_ctx: + freebuf(req_hdr); + oap_ctx_free(ctx); + fail_prepare: + reg_destroy_flow(flow->id); + fail_flow: + return err; +} + +/* Completes the key exchange once the IPCP has the peer's response. */ +/* + * We present the PoA's own credentials and expect the peer to present + * dst's: the address only says how to reach it. oap_cli_complete + * frees the ctx on every path. + */ +static int poa_complete(struct flow_info * flow, + int response, + buffer_t * data, + struct crypt_sk * sk) +{ + struct name_info info; + buffer_t peer_crt = BUF_INIT; + buffer_t out = BUF_INIT; + buffer_t empty = BUF_INIT; + char name[NAME_SIZE + 1]; + void * ctx; + int err; + + ctx = reg_flow_take_oap_ctx(flow->id); + if (ctx == NULL) { + log_err("No pending PoA flow %d.", flow->id); + return -EBADF; + } + + if (response < 0) { + log_dbg("PoA flow %d refused: %d.", flow->id, response); + + err = response; + goto fail; + } + + if (reg_get_name_for_flow_id(name, flow->id) < 0) { + err = -EBADF; + goto fail; + } + + poa_name_info(name, &info); + + err = oap_cli_complete(ctx, *data, &out, sk, NULL, &peer_crt); + if (err < 0) { + log_err("OAP completion failed for %s.", name); + + ctx = NULL; + goto fail; + } + + if (sk->nid != NID_undef) + reg_flow_set_rekey(flow->id, true, peer_crt); + + flow->state = FLOW_ALLOCATED; + if (reg_respond_alloc(flow, &empty, 0) < 0) { + log_err("Failed to update PoA flow %d.", flow->id); + + err = -EBADF; + goto fail_crt; + } + + log_info("PoA flow %d allocated to %s.", flow->id, name); + + freebuf(peer_crt); + freebuf(out); + + return 0; + + fail_crt: + freebuf(peer_crt); + freebuf(out); + fail: + oap_ctx_free(ctx); + reg_destroy_flow(flow->id); + return err; +} + +/* A peer requested a flow on a PoA of this IPCP. */ +static int poa_req_arr(struct flow_info * flow, + buffer_t * data) +{ + struct ipcp_info ipcp; + struct layer_info layer; + int ret; + + ipcp.pid = flow->n_1_pid; + if (reg_get_ipcp(&ipcp, &layer) < 0) { + log_err("No IPCP with pid %d.", flow->n_1_pid); + + ret = -EIPCP; + goto fail; + } + + log_info("PoA flow request arrived for %s.", ipcp.name); + + ret = wait_for_accept(ipcp.name); + if (ret < 0) { + log_err("No active process for %s.", ipcp.name); + goto fail; + } + + flow->id = ret; + flow->state = FLOW_ALLOCATED; + if (reg_flow_set_poa(flow->id) < 0) { + ret = -EBADF; + goto fail; + } + + reg_set_name_for_flow_id(ipcp.name, flow->id); + + ret = reg_respond_accept(flow, data); + if (ret < 0) { + log_err("Failed to respond to PoA flow %d.", flow->id); + goto fail; + } + + return 0; + fail: + return ret; +} + static int flow_alloc_reply(struct flow_info * flow, int response, buffer_t * data) @@ -1596,6 +2007,11 @@ static int rekey_name_info(int flow_id, if (reg_get_name_for_flow_id(name, flow_id) < 0) return -1; + if (reg_flow_is_poa(flow_id)) { + poa_name_info(name, info); + return 0; + } + return reg_get_name_info(name, info); } @@ -1667,7 +2083,7 @@ static void rekey_do_initiate(struct list_head * tbl, goto fail; } - if (oap_cli_prepare(&ctx, &name, &req, data, true) < 0) { + if (oap_cli_prepare(&ctx, &name, NULL, &req, data, true) < 0) { log_err("Failed to prepare re-key for flow %d.", flow_id); goto fail; } @@ -1758,7 +2174,7 @@ static void rekey_do_complete(struct list_head * tbl, reg_flow_get_peer_crt(flow_id, &crt); /* oap_cli_complete frees the ctx on every path. */ - if (oap_cli_complete(e->ctx, &info, buf, &data, &sk, &crt, NULL) < 0) { + if (oap_cli_complete(e->ctx, buf, &data, &sk, &crt, NULL) < 0) { log_warn("Failed to complete re-key for flow %d.", flow_id); e->ctx = NULL; goto finish_clear; @@ -1933,7 +2349,7 @@ static void rekey_do_direct(int flow_id) return; } - if (oap_cli_prepare(&ctx, &info, &req, data, true) < 0) { + if (oap_cli_prepare(&ctx, &info, NULL, &req, data, true) < 0) { log_err("Failed to prepare re-key for flow %d.", flow_id); reg_flow_clear_in_flight(flow_id); return; @@ -2307,6 +2723,10 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg, pid_t cpid; irm_msg_t * ret_msg; buffer_t data; + struct poa_addr poa_addr; + struct poa_addr * pa; + struct poa_spec poa_spec; + struct poa_spec * eps = NULL; memset(&flow, 0, sizeof(flow)); @@ -2350,11 +2770,74 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg, res = bootstrap_ipcp(msg->pid, &conf); break; case IRM_MSG_CODE__IRM_ENROLL_IPCP: - res = enroll_ipcp(msg->pid, msg->dst); + if (msg->peer != NULL) { + poa_addr = poa_addr_msg_to_s(msg->peer); + if (poa_addr.type == POA_INVALID) { + res = -EINVAL; + break; + } + } + + if (msg->conf != NULL) + conf = ipcp_config_msg_to_s(msg->conf); + res = enroll_ipcp_resolve(msg->pid, msg->dst, + msg->peer != NULL ? &poa_addr : NULL); + break; + case IRM_MSG_CODE__IRM_ATTACH_IPCP: + poa_spec = poa_spec_msg_to_s(msg->poa); + if (poa_spec.type == POA_INVALID) { + res = -EINVAL; + break; + } + + res = attach_ipcp(msg->pid, &poa_spec, true); + break; + case IRM_MSG_CODE__IRM_DETACH_IPCP: + poa_spec = poa_spec_msg_to_s(msg->poa); + if (poa_spec.type == POA_INVALID) { + res = -EINVAL; + break; + } + + res = attach_ipcp(msg->pid, &poa_spec, false); + break; + case IRM_MSG_CODE__IRM_LIST_POAS: + res = list_poas(msg->pid, &eps); + if (res > 0) { + ssize_t i; + ret_msg->poas = malloc(res * sizeof(*ret_msg->poas)); + if (ret_msg->poas == NULL) { + free(eps); + + res = -ENOMEM; + break; + } + for (i = 0; i < res; i++) { + ret_msg->poas[i] = poa_spec_s_to_msg(&eps[i]); + if (ret_msg->poas[i] == NULL) + break; + ret_msg->n_poas++; + } + res = i == res ? 0 : -ENOMEM; + } + free(eps); break; case IRM_MSG_CODE__IRM_CONNECT_IPCP: flow.qs = qos_spec_msg_to_s(msg->qosspec); - res = connect_ipcp(msg->pid, msg->dst, msg->comp, flow.qs); + + pa = NULL; + + if (msg->peer != NULL) { + poa_addr = poa_addr_msg_to_s(msg->peer); + if (poa_addr.type == POA_INVALID) { + res = -EINVAL; + break; + } + pa = &poa_addr; + } + + res = connect_ipcp_resolve(msg->pid, msg->dst, msg->comp, + flow.qs, pa); break; case IRM_MSG_CODE__IRM_DISCONNECT_IPCP: res = disconnect_ipcp(msg->pid, msg->dst, msg->comp); @@ -2499,6 +2982,67 @@ static irm_msg_t * do_command_msg(irm_msg_t * msg, if (res == 0) ret_msg->flow_info = flow_info_s_to_msg(&flow); break; + case IRM_MSG_CODE__IRM_POA_FLOW_ALLOC: + flow = flow_info_msg_to_s(msg->flow_info); + + clrbuf(data); + + res = poa_alloc(&flow, msg->dst, &data); + if (res == 0) { + ret_msg->flow_info = flow_info_s_to_msg(&flow); + ret_msg->has_pk = true; + ret_msg->pk.len = data.len; + ret_msg->pk.data = data.data; + + clrbuf(data); + } + break; + case IRM_MSG_CODE__IRM_POA_FLOW_ALLOC_R: + data.len = msg->pk.len; + data.data = msg->pk.data; + msg->pk.data = NULL; /* pass data */ + msg->pk.len = 0; + flow = flow_info_msg_to_s(msg->flow_info); + sk.key = kbuf; + res = poa_complete(&flow, msg->response, &data, &sk); + + freebuf(data); + + if (res != 0) + break; + + ret_msg->flow_info = flow_info_s_to_msg(&flow); + ret_msg->has_cipher_nid = true; + ret_msg->cipher_nid = sk.nid; + + if (sk.nid == NID_undef) + break; + + hbuf = malloc(SYMMKEYSZ); + if (hbuf == NULL) { + log_err("Failed to malloc key buf"); + + res = -ENOMEM; + break; + } + + memcpy(hbuf, kbuf, SYMMKEYSZ); + + ret_msg->sym_key.data = hbuf; + ret_msg->sym_key.len = SYMMKEYSZ; + ret_msg->has_sym_key = true; + break; + case IRM_MSG_CODE__IPCP_POA_FLOW_REQ_ARR: + data.len = msg->pk.len; + data.data = msg->pk.data; + msg->pk.data = NULL; /* pass data */ + msg->pk.len = 0; + flow = flow_info_msg_to_s(msg->flow_info); + + res = poa_req_arr(&flow, &data); + if (res == 0) + ret_msg->flow_info = flow_info_s_to_msg(&flow); + break; case IRM_MSG_CODE__IPCP_FLOW_ALLOC_REPLY: data.len = msg->pk.len; data.data = msg->pk.data; diff --git a/src/irmd/oap.h b/src/irmd/oap.h index 86f11e21..e9d7511b 100644 --- a/src/irmd/oap.h +++ b/src/irmd/oap.h @@ -40,21 +40,21 @@ int oap_auth_add_ca_crt(void * crt); int oap_auth_add_chain_crt(void * crt); /* -* Prepare OAP request header for server, returns context -* Passes client data for srv, returns srv data for client -* rekey forces ephemeral server-encap KEX (no client-encap; preserves FS/PCS) -*/ + * Prepares the request header and returns the context. info holds the + * credentials we present, peer the name the server certificate must + * carry (NULL expects info->name); rekey forces an ephemeral KEX. + */ int oap_cli_prepare(void ** ctx, const struct name_info * info, + const char * peer, buffer_t * req_buf, buffer_t data, bool rekey); /* - * Server processes header, creates response header, returns secret key. - * data is in/out: input=srv data to send, output=cli data received. - * rekey drops the cert and verifies against cached_crt; peer_crt (or NULL) - * receives a copy of the peer cert to cache at the initial handshake. + * Answers the request header and returns the secret key. data is + * in/out; rekey verifies against cached_crt, and peer_crt takes a copy + * of the peer cert to cache at the initial handshake. */ int oap_srv_process(const struct name_info * info, buffer_t req_buf, @@ -70,13 +70,12 @@ int oap_srv_process(const struct name_info * info, * cached_crt verifies a cert-less re-key; peer_crt (or NULL) receives a * copy of the peer cert to cache at the initial handshake. */ -int oap_cli_complete(void * ctx, - const struct name_info * info, - buffer_t rsp_buf, - buffer_t * data, - struct crypt_sk * sk, - const buffer_t * cached_crt, - buffer_t * peer_crt); +int oap_cli_complete(void * ctx, + buffer_t rsp_buf, + buffer_t * data, + struct crypt_sk * sk, + const buffer_t * cached_crt, + buffer_t * peer_crt); /* Free OAP state (on failure before complete) */ void oap_ctx_free(void * ctx); diff --git a/src/irmd/oap/cli.c b/src/irmd/oap/cli.c index ebfcd71f..2203596f 100644 --- a/src/irmd/oap/cli.c +++ b/src/irmd/oap/cli.c @@ -50,6 +50,7 @@ struct oap_cli_ctx { uint8_t __id[OAP_ID_SIZE]; buffer_t id; + char peer[NAME_SIZE + 1]; /* expected server name */ uint8_t kex_buf[CRYPT_KEY_BUFSZ]; uint8_t req_hash[MAX_HASH_SIZE]; size_t req_hash_len; @@ -241,6 +242,7 @@ static int do_client_kex_prepare(const char * server_name, int oap_cli_prepare(void ** ctx, const struct name_info * info, + const char * peer, buffer_t * req_buf, buffer_t data, bool rekey) @@ -259,6 +261,11 @@ int oap_cli_prepare(void ** ctx, clrbuf(*req_buf); *ctx = NULL; + if (peer != NULL && strlen(peer) > NAME_SIZE) { + log_err("Peer name too long."); + return -EINVAL; + } + /* Allocate ctx to carry between prepare and complete */ s = malloc(sizeof(*s)); if (s == NULL) { @@ -269,13 +276,15 @@ int oap_cli_prepare(void ** ctx, memset(s, 0, sizeof(*s)); OAP_CLI_CTX_INIT(s); + strcpy(s->peer, peer != NULL ? peer : info->name); + /* Generate session ID */ if (random_buffer(s->__id, OAP_ID_SIZE) < 0) { log_err("Failed to generate OAP session ID."); goto fail_id; } - log_dbg_id(s->id.data, "Preparing OAP request for %s.", info->name); + log_dbg_id(s->id.data, "Preparing OAP request for %s.", s->peer); /* Load client credentials */ if (load_cli_credentials(info, &pkp, &crt) < 0) { @@ -315,7 +324,7 @@ int oap_cli_prepare(void ** ctx, oap_hdr_init(&s->local_hdr, s->id, s->kex_buf, data, s->scfg.c.nid); - if (do_client_kex_prepare(info->name, s) < 0) { + if (do_client_kex_prepare(s->peer, s) < 0) { log_err_id(s->id.data, "Failed to prepare client KEX."); goto fail_kex; } @@ -482,7 +491,8 @@ static int do_client_kex_complete(struct oap_cli_ctx * s, } SET_KEX_CIPHER(scfg, peer_hdr->cipher_str); - if (crypt_validate_nid(scfg->c.nid) < 0) { + + if (crypt_cipher_rank(scfg->c.nid) < 0) { log_err_id(id, "Server cipher '%s' not supported.", peer_hdr->cipher_str); return -ENOTSUP; @@ -518,13 +528,12 @@ static int do_client_kex_complete(struct oap_cli_ctx * s, return do_client_kex_complete_dhe(s, peer_hdr, sk); } -int oap_cli_complete(void * ctx, - const struct name_info * info, - buffer_t rsp_buf, - buffer_t * data, - struct crypt_sk * sk, - const buffer_t * cached_crt, - buffer_t * peer_crt) +int oap_cli_complete(void * ctx, + buffer_t rsp_buf, + buffer_t * data, + struct crypt_sk * sk, + const buffer_t * cached_crt, + buffer_t * peer_crt) { struct oap_cli_ctx * s = ctx; struct oap_hdr peer_hdr; @@ -538,7 +547,6 @@ int oap_cli_complete(void * ctx, int rc; assert(ctx != NULL); - assert(info != NULL); assert(data != NULL); assert(sk != NULL); @@ -550,7 +558,7 @@ int oap_cli_complete(void * ctx, id = s->id.data; - log_dbg_id(id, "Completing OAP for %s.", info->name); + log_dbg_id(id, "Completing OAP for %s.", s->peer); /* Decode response header using client's md_nid for hash length */ if (oap_hdr_decode(&peer_hdr, rsp_buf, s->req_md_nid, false) < 0) { @@ -616,9 +624,9 @@ int oap_cli_complete(void * ctx, } /* Verify peer certificate name matches expected destination */ - if (peer_hdr.crt.len > 0 && strcmp(peer, info->name) != 0) { + if (peer_hdr.crt.len > 0 && strcmp(peer, s->peer) != 0) { log_err_id(id, "Peer crt for '%s' does not match '%s'.", - peer, info->name); + peer, s->peer); goto fail_oap; } @@ -667,7 +675,7 @@ int oap_cli_complete(void * ctx, goto fail_oap; } - log_info_id(id, "OAP completed for %s.", info->name); + log_info_id(id, "OAP completed for %s.", s->peer); freebuf(peer_hdr.sealed_pt); diff --git a/src/irmd/oap/tests/common.c b/src/irmd/oap/tests/common.c index 16d52c63..b65f3997 100644 --- a/src/irmd/oap/tests/common.c +++ b/src/irmd/oap/tests/common.c @@ -159,7 +159,7 @@ void oap_test_teardown(struct oap_test_ctx * ctx) if (ctx->cli.state != NULL) { res.key = ctx->cli.key; - oap_cli_complete(ctx->cli.state, &ctx->cli.info, dummy, + oap_cli_complete(ctx->cli.state, dummy, &ctx->data, &res, NULL, NULL); ctx->cli.state = NULL; } @@ -179,8 +179,8 @@ void oap_test_teardown(struct oap_test_ctx * ctx) int oap_cli_prepare_ctx(struct oap_test_ctx * ctx) { - return oap_cli_prepare(&ctx->cli.state, &ctx->cli.info, &ctx->req_hdr, - ctx->data, ctx->rekey); + return oap_cli_prepare(&ctx->cli.state, &ctx->cli.info, NULL, + &ctx->req_hdr, ctx->data, ctx->rekey); } int oap_srv_process_ctx(struct oap_test_ctx * ctx) @@ -203,8 +203,7 @@ int oap_cli_complete_ctx(struct oap_test_ctx * ctx) struct crypt_sk res = { .nid = NID_undef, .key = ctx->cli.key }; int ret; - ret = oap_cli_complete(ctx->cli.state, &ctx->cli.info, ctx->resp_hdr, - &ctx->data, &res, + ret = oap_cli_complete(ctx->cli.state, ctx->resp_hdr, &ctx->data, &res, ctx->rekey ? &ctx->cli_crt : NULL, ctx->rekey ? NULL : &ctx->cli_crt); ctx->cli.state = NULL; @@ -527,7 +526,7 @@ int roundtrip_kex_only(void) goto fail; } - if (oap_cli_prepare(&cli_state, &cli_info, &req_hdr, + if (oap_cli_prepare(&cli_state, &cli_info, NULL, &req_hdr, data, false) < 0) { printf("Client prepare failed.\n"); goto fail_cleanup; @@ -545,7 +544,7 @@ int roundtrip_kex_only(void) res.key = cli_key; - if (oap_cli_complete(cli_state, &cli_info, resp_hdr, &data, &res, + if (oap_cli_complete(cli_state, resp_hdr, &data, &res, NULL, NULL) < 0) { printf("Client complete failed.\n"); cli_state = NULL; @@ -575,8 +574,8 @@ int roundtrip_kex_only(void) fail_cleanup: if (cli_state != NULL) { res.key = cli_key; - oap_cli_complete(cli_state, &cli_info, resp_hdr, &data, - &res, NULL, NULL); + + oap_cli_complete(cli_state, resp_hdr, &data, &res, NULL, NULL); } freebuf(resp_hdr); freebuf(req_hdr); @@ -655,7 +654,7 @@ int corrupted_response(const char * root_ca, res.key = ctx.cli.key; - if (oap_cli_complete(ctx.cli.state, &ctx.cli.info, ctx.resp_hdr, + if (oap_cli_complete(ctx.cli.state, ctx.resp_hdr, &ctx.data, &res, NULL, NULL) == 0) { printf("Client should reject corrupted response.\n"); ctx.cli.state = NULL; diff --git a/src/irmd/reg/flow.c b/src/irmd/reg/flow.c index 8be2dfc7..63c9199b 100644 --- a/src/irmd/reg/flow.c +++ b/src/irmd/reg/flow.c @@ -126,6 +126,9 @@ static int create_rbuffs(struct reg_flow * flow, assert(flow->n_1_rb == NULL); flow->info.n_1_pid = info->n_1_pid; + if (flow->poa) + return 0; + flow->n_1_rb = ssm_rbuff_create(info->n_1_pid, info->id); if (flow->n_1_rb == NULL) goto fail_n_1_rb; diff --git a/src/irmd/reg/flow.h b/src/irmd/reg/flow.h index 166bed61..c7021a0f 100644 --- a/src/irmd/reg/flow.h +++ b/src/irmd/reg/flow.h @@ -48,6 +48,8 @@ struct reg_flow { char name[NAME_SIZE + 1]; bool direct; + bool poa; /* transport is a point of attachment */ + void * oap_ctx; /* key exchange, prepare -> complete */ /* Tier-2 re-key state (encrypted flows only) */ struct { diff --git a/src/irmd/reg/name.c b/src/irmd/reg/name.c index a3621fc3..08426033 100644 --- a/src/irmd/reg/name.c +++ b/src/irmd/reg/name.c @@ -1,4 +1,3 @@ - /* * Ouroboros - Copyright (C) 2016 - 2026 * diff --git a/src/irmd/reg/reg.c b/src/irmd/reg/reg.c index ebf3959d..a302fa15 100644 --- a/src/irmd/reg/reg.c +++ b/src/irmd/reg/reg.c @@ -2119,6 +2119,77 @@ bool reg_flow_is_direct(int flow_id) return ret; } +bool reg_flow_is_poa(int flow_id) +{ + struct reg_flow * flow; + bool ret; + + pthread_mutex_lock(®.mtx); + + flow = __reg_get_flow(flow_id); + + ret = flow != NULL && flow->poa; + + pthread_mutex_unlock(®.mtx); + + return ret; +} + +int reg_flow_set_poa(int flow_id) +{ + struct reg_flow * flow; + int ret = -1; + + pthread_mutex_lock(®.mtx); + + flow = __reg_get_flow(flow_id); + if (flow != NULL) { + flow->poa = true; + ret = 0; + } + + pthread_mutex_unlock(®.mtx); + + return ret; +} + +int reg_flow_set_oap_ctx(int flow_id, + void * ctx) +{ + struct reg_flow * flow; + int ret = -1; + + pthread_mutex_lock(®.mtx); + + flow = __reg_get_flow(flow_id); + if (flow != NULL) { + flow->oap_ctx = ctx; + ret = 0; + } + + pthread_mutex_unlock(®.mtx); + + return ret; +} + +void * reg_flow_take_oap_ctx(int flow_id) +{ + struct reg_flow * flow; + void * ctx = NULL; + + pthread_mutex_lock(®.mtx); + + flow = __reg_get_flow(flow_id); + if (flow != NULL) { + ctx = flow->oap_ctx; + flow->oap_ctx = NULL; + } + + pthread_mutex_unlock(®.mtx); + + return ctx; +} + void reg_flow_set_rekey(int flow_id, bool initiator, buffer_t peer_crt) @@ -2607,7 +2678,7 @@ void reg_notify_flow(int flow_id, pthread_mutex_unlock(®.mtx); } -/* Wake both endpoints of a direct flow (acceptor and allocator). */ +/* Wake both PoAs of a direct flow (acceptor and allocator). */ void reg_notify_flow_peers(int flow_id, int event) { diff --git a/src/irmd/reg/reg.h b/src/irmd/reg/reg.h index 8a313d46..6882532c 100644 --- a/src/irmd/reg/reg.h +++ b/src/irmd/reg/reg.h @@ -33,138 +33,147 @@ #include "pool.h" -int reg_init(void); +int reg_init(void); -void reg_clear(void); +void reg_clear(void); -void reg_fini(void); +void reg_fini(void); -int reg_create_flow(struct flow_info * info); +int reg_create_flow(struct flow_info * info); -int reg_destroy_flow(int flow_id); +int reg_destroy_flow(int flow_id); -bool reg_has_flow(int flow_id); +bool reg_has_flow(int flow_id); -int reg_create_proc(const struct proc_info * info); +int reg_create_proc(const struct proc_info * info); /* Use this for all processes, including ipcps */ -int reg_destroy_proc(pid_t pid); +int reg_destroy_proc(pid_t pid); -bool reg_has_proc(pid_t pid); +bool reg_has_proc(pid_t pid); -bool reg_is_proc_privileged(pid_t pid); +bool reg_is_proc_privileged(pid_t pid); -int reg_prepare_pool(uid_t uid, - gid_t gid); +int reg_prepare_pool(uid_t uid, + gid_t gid); -uid_t reg_get_proc_uid(pid_t pid); +uid_t reg_get_proc_uid(pid_t pid); -void reg_kill_all_proc(int signal); +void reg_kill_all_proc(int signal); -pid_t reg_get_dead_proc(void); +pid_t reg_get_dead_proc(void); -int reg_create_spawned(pid_t pid); +int reg_create_spawned(pid_t pid); -bool reg_has_spawned(pid_t pid); +bool reg_has_spawned(pid_t pid); -void reg_kill_all_spawned(int signal); +void reg_kill_all_spawned(int signal); -int reg_first_spawned(void); +int reg_first_spawned(void); -int reg_bind_proc(const char * name, - pid_t proc); +int reg_bind_proc(const char * name, + pid_t proc); -int reg_unbind_proc(const char * name, - pid_t proc); +int reg_unbind_proc(const char * name, + pid_t proc); -int reg_create_ipcp(const struct ipcp_info * info); +int reg_create_ipcp(const struct ipcp_info * info); -bool reg_has_ipcp(pid_t pid); +bool reg_has_ipcp(pid_t pid); -int reg_set_layer_for_ipcp(struct ipcp_info * info, - const struct layer_info * layer); +int reg_set_layer_for_ipcp(struct ipcp_info * info, + const struct layer_info * layer); -int reg_get_ipcp(struct ipcp_info * info, - struct layer_info * layer); +int reg_get_ipcp(struct ipcp_info * info, + struct layer_info * layer); -int reg_get_ipcp_by_layer(struct ipcp_info * info, - struct layer_info * layer); +int reg_get_ipcp_by_layer(struct ipcp_info * info, + struct layer_info * layer); /* TODO don't rely on protobuf here */ -int reg_list_ipcps(ipcp_list_msg_t *** msg); +int reg_list_ipcps(ipcp_list_msg_t *** msg); -int reg_create_name(const struct name_info * info); +int reg_create_name(const struct name_info * info); -int reg_destroy_name(const char * name); +int reg_destroy_name(const char * name); -bool reg_has_name(const char * name); +bool reg_has_name(const char * name); -int reg_get_name_info(const char * name, - struct name_info * info); +int reg_get_name_info(const char * name, + struct name_info * info); -int reg_get_name_for_hash(char * buf, - enum hash_algo algo, - const uint8_t * hash); +int reg_get_name_for_hash(char * buf, + enum hash_algo algo, + const uint8_t * hash); -int reg_get_name_for_flow_id(char * buf, - int flow_id); +int reg_get_name_for_flow_id(char * buf, + int flow_id); -void reg_set_name_for_flow_id(const char * name, - int flow_id); +void reg_set_name_for_flow_id(const char * name, + int flow_id); /* TODO don't rely on protobuf here */ -int reg_list_names(name_info_msg_t *** names); +int reg_list_names(name_info_msg_t *** names); -int reg_create_prog(const struct prog_info * info); +int reg_create_prog(const struct prog_info * info); -int reg_destroy_prog(const char * name); +int reg_destroy_prog(const char * name); -bool reg_has_prog(const char * name); +bool reg_has_prog(const char * name); -int reg_get_exec(const char * name, - char *** exec); +int reg_get_exec(const char * name, + char *** exec); -int reg_bind_prog(const char * name, - char ** exec, - uint8_t flags); +int reg_bind_prog(const char * name, + char ** exec, + uint8_t flags); -int reg_unbind_prog(const char * name, - const char * prog); +int reg_unbind_prog(const char * name, + const char * prog); -int reg_prepare_flow_alloc(struct flow_info * info); +int reg_prepare_flow_alloc(struct flow_info * info); -int reg_wait_flow_allocated(struct flow_info * info, +int reg_wait_flow_allocated(struct flow_info * info, + buffer_t * pbuf, + const struct timespec * abstime); + +int reg_respond_alloc(struct flow_info * info, + buffer_t * pbuf, + int response); + +int reg_prepare_flow_accept(struct flow_info * info); + +int reg_wait_flow_accepted(struct flow_info * info, buffer_t * pbuf, const struct timespec * abstime); -int reg_respond_alloc(struct flow_info * info, - buffer_t * pbuf, - int response); +int reg_wait_flow_accepting(const char * name, + const struct timespec * abstime); -int reg_prepare_flow_accept(struct flow_info * info); +int reg_respond_accept(struct flow_info * info, + buffer_t * pbuf); -int reg_wait_flow_accepted(struct flow_info * info, - buffer_t * pbuf, - const struct timespec * abstime); +int reg_prepare_flow_direct(struct flow_info * info, + buffer_t * pbuf, + uid_t alloc_uid); -int reg_wait_flow_accepting(const char * name, - const struct timespec * abstime); +int reg_respond_flow_direct(int flow_id, + buffer_t * pbuf); + +int reg_wait_flow_direct(int flow_id, + buffer_t * pbuf, + const struct timespec * abstime); -int reg_respond_accept(struct flow_info * info, - buffer_t * pbuf); +bool reg_flow_is_direct(int flow_id); -int reg_prepare_flow_direct(struct flow_info * info, - buffer_t * pbuf, - uid_t alloc_uid); +bool reg_flow_is_poa(int flow_id); -int reg_respond_flow_direct(int flow_id, - buffer_t * pbuf); +int reg_flow_set_poa(int flow_id); -int reg_wait_flow_direct(int flow_id, - buffer_t * pbuf, - const struct timespec * abstime); +int reg_flow_set_oap_ctx(int flow_id, + void * ctx); -bool reg_flow_is_direct(int flow_id); +void * reg_flow_take_oap_ctx(int flow_id); /* Per-flow snapshot for the re-key timer */ struct rekey_info { @@ -176,70 +185,70 @@ struct rekey_info { bool direct; }; -void reg_flow_set_rekey(int flow_id, - bool initiator, - buffer_t peer_crt); +void reg_flow_set_rekey(int flow_id, + bool initiator, + buffer_t peer_crt); -int reg_flow_get_peer_crt(int flow_id, - buffer_t * crt); +int reg_flow_get_peer_crt(int flow_id, + buffer_t * crt); -int reg_flow_get_epoch(int flow_id); +int reg_flow_get_epoch(int flow_id); -bool reg_flow_rekey_pending(int flow_id); +bool reg_flow_rekey_pending(int flow_id); -pid_t reg_flow_get_n_1_pid(int flow_id); +pid_t reg_flow_get_n_1_pid(int flow_id); -int reg_flow_snapshot_rekey_due(struct rekey_info * snap, - int max); +int reg_flow_snapshot_rekey_due(struct rekey_info * snap, + int max); -void reg_flow_clear_in_flight(int flow_id); +void reg_flow_clear_in_flight(int flow_id); -bool reg_flow_rekey_begin(int flow_id); +bool reg_flow_rekey_begin(int flow_id); -bool reg_flow_rekey_should_yield(int flow_id); +bool reg_flow_rekey_should_yield(int flow_id); -int reg_flow_store_pending(int flow_id, - const uint8_t * seed, - uint8_t epoch, - bool initiator); +int reg_flow_store_pending(int flow_id, + const uint8_t * seed, + uint8_t epoch, + bool initiator); -int reg_flow_store_pending_direct(int flow_id, - const uint8_t * seed, - uint8_t epoch); +int reg_flow_store_pending_direct(int flow_id, + const uint8_t * seed, + uint8_t epoch); -int reg_flow_take_pending(int flow_id, - uid_t uid, - pid_t cpid, - uint8_t * seed, - uint8_t * epoch, - bool * initiator); +int reg_flow_take_pending(int flow_id, + uid_t uid, + pid_t cpid, + uint8_t * seed, + uint8_t * epoch, + bool * initiator); -bool reg_flow_rekey_arr_admit(int flow_id, - pid_t n_1_pid, - bool is_req); +bool reg_flow_rekey_arr_admit(int flow_id, + pid_t n_1_pid, + bool is_req); -void reg_flow_rekey_arr_done(int flow_id, - bool is_req); +void reg_flow_rekey_arr_done(int flow_id, + bool is_req); -bool reg_flow_owned_by(int flow_id, - uid_t uid); +bool reg_flow_owned_by(int flow_id, + uid_t uid); -void reg_notify_flow(int flow_id, - int event); +void reg_notify_flow(int flow_id, + int event); -void reg_notify_flow_peers(int flow_id, - int event); +void reg_notify_flow_peers(int flow_id, + int event); -void reg_dealloc_flow(struct flow_info * info); +void reg_dealloc_flow(struct flow_info * info); -void reg_dealloc_flow_resp(struct flow_info * info); +void reg_dealloc_flow_resp(struct flow_info * info); -int reg_wait_proc(pid_t pid, - const struct timespec * abstime); +int reg_wait_proc(pid_t pid, + const struct timespec * abstime); -int reg_wait_ipcp_boot(struct ipcp_info * ipcp, - const struct timespec * abstime); +int reg_wait_ipcp_boot(struct ipcp_info * ipcp, + const struct timespec * abstime); -int reg_respond_ipcp(const struct ipcp_info * info); +int reg_respond_ipcp(const struct ipcp_info * info); #endif /* OUROBOROS_IRMD_REG_H */ diff --git a/src/irmd/reg/tests/reg_test.c b/src/irmd/reg/tests/reg_test.c index a8c1b1fa..ab57241c 100644 --- a/src/irmd/reg/tests/reg_test.c +++ b/src/irmd/reg/tests/reg_test.c @@ -746,7 +746,7 @@ static int test_reg_direct_flow_success(void) reg_dealloc_flow(&info); if (info.state != FLOW_DEALLOC_PENDING) { - printf("Same endpoint dealloc changed state.\n"); + printf("Same PoA dealloc changed state.\n"); goto fail; } -- cgit v1.2.3