diff options
Diffstat (limited to 'src/tools')
29 files changed, 1093 insertions, 239 deletions
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 6b418838..bb601733 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -15,6 +15,10 @@ set(IRM_SOURCES irm/irm_ipcp_destroy.c irm/irm_ipcp_bootstrap.c irm/irm_ipcp_enroll.c + irm/irm_ipcp_poa.c + irm/irm_ipcp_poa_attach.c + irm/irm_ipcp_poa_detach.c + irm/irm_ipcp_poa_list.c irm/irm_ipcp_list.c irm/irm_ipcp_connect.c irm/irm_ipcp_disconnect.c diff --git a/src/tools/irm/irm_bind.c b/src/tools/irm/irm_bind.c index 3107837a..2d3fc554 100644 --- a/src/tools/irm/irm_bind.c +++ b/src/tools/irm/irm_bind.c @@ -78,8 +78,8 @@ static int do_cmd(const char * argv0, const struct cmd * c; for (c = cmds; c->cmd; ++c) { - if (!matches(argv0, c->cmd)) - return c->func(argc, argv); + if (matches(argv0, c->cmd) == 0) + return c->func(argc - 1, argv + 1); } fprintf(stderr, "\"%s\" is unknown, try \"irm bind help\".\n", argv0); diff --git a/src/tools/irm/irm_bind_ipcp.c b/src/tools/irm/irm_bind_ipcp.c index 4c183534..b6223074 100644 --- a/src/tools/irm/irm_bind_ipcp.c +++ b/src/tools/irm/irm_bind_ipcp.c @@ -61,15 +61,20 @@ int do_bind_ipcp(int argc, ssize_t len; ssize_t i; + if (argc < 1) { + usage(); + return -1; + } + + ipcp = *argv; + ++argv; + --argc; + while (argc > 0) { if (matches(*argv, "name") == 0) { name = *(argv + 1); ++argv; --argc; - } else if (matches(*argv, "ipcp") == 0) { - ipcp = *(argv + 1); - ++argv; - --argc; } else { printf("\"%s\" is unknown, try \"irm " "bind ipcp\".\n", *argv); diff --git a/src/tools/irm/irm_bind_process.c b/src/tools/irm/irm_bind_process.c index fee0c46b..c401df14 100644 --- a/src/tools/irm/irm_bind_process.c +++ b/src/tools/irm/irm_bind_process.c @@ -61,20 +61,24 @@ int do_bind_process(int argc, char * name = NULL; char * t; + if (argc < 1) { + usage(); + return -1; + } + + pid = strtol(*argv, &t, 10); + if (*argv == t || *t != '\0' || kill(pid, 0)) { + printf("\"%s\" is not a valid process id.\n", *argv); + return -1; + } + ++argv; + --argc; + while (argc > 1) { if (matches(*argv, "name") == 0) { name = *(argv + 1); ++argv; --argc; - } else if (matches(*argv, "process") == 0) { - pid = strtol(*(argv + 1), &t, 10); - if (*(argv + 1) == t || *t != '\0' || kill(pid, 0)) { - printf("\"%s\" is not a valid process id.\n", - *(argv + 1)); - return -1; - } - ++argv; - --argc; } else { printf("\"%s\" is unknown, try \"irm " "bind process\".\n", *argv); diff --git a/src/tools/irm/irm_bind_program.c b/src/tools/irm/irm_bind_program.c index 14d09db7..592c2ec3 100644 --- a/src/tools/irm/irm_bind_program.c +++ b/src/tools/irm/irm_bind_program.c @@ -67,18 +67,23 @@ int do_bind_program(int argc, int ret = 0; char * temp = NULL; + if (argc < 1) { + usage(); + return -1; + } + + temp = realpath(*argv, NULL); + if (temp != NULL) + *argv = temp; + prog = *argv; + ++argv; + --argc; + while (argc > 0) { if (matches(*argv, "name") == 0) { name = *(argv + 1); ++argv; --argc; - } else if (matches(*argv, "program") == 0) { - ++argv; - temp = realpath(*argv, NULL); - if (temp != NULL) - *argv = temp; - prog = *argv; - --argc; } else if (strcmp(*argv, "auto") == 0) { flags |= BIND_AUTO; } else if (strcmp(*argv, "--") == 0) { diff --git a/src/tools/irm/irm_ipcp.c b/src/tools/irm/irm_ipcp.c index 34458a20..5c0db9cf 100644 --- a/src/tools/irm/irm_ipcp.c +++ b/src/tools/irm/irm_ipcp.c @@ -46,6 +46,7 @@ static void usage(void) printf("Usage: irm ipcp [OPERATION]\n\n" "where OPERATION in {create destroy\n" " bootstrap enroll\n" + " poa\n" " connect disconnect\n" " list\n" " help}\n"); @@ -68,6 +69,7 @@ static const struct cmd { { "destroy", do_destroy_ipcp }, { "bootstrap", do_bootstrap_ipcp }, { "enroll", do_enroll_ipcp }, + { "poa", poa_cmd }, { "connect", do_connect_ipcp }, { "disconnect", do_disconnect_ipcp }, { "list", do_list_ipcp}, diff --git a/src/tools/irm/irm_ipcp_bootstrap.c b/src/tools/irm/irm_ipcp_bootstrap.c index cc8bf8fa..bbcf2312 100644 --- a/src/tools/irm/irm_ipcp_bootstrap.c +++ b/src/tools/irm/irm_ipcp_bootstrap.c @@ -53,10 +53,6 @@ #define UNICAST "unicast" #define BROADCAST "broadcast" -#define IP_UDP4 "udp4" -#define IP_UDP6 "udp6" -#define ETH_LLC "eth-llc" -#define ETH_DIX "eth-dix" #define LOCAL "local" #define MD5 "MD5" @@ -76,18 +72,13 @@ #define DT(x) default_dt_config.x #define DHT(x) default_dht_config.params.x #define UNI(x) default_uni_config.x -#define DIX(x) eth_dix_default_conf.eth.x -#define LLC(x) eth_llc_default_conf.eth.x -#define UD4(x) udp4_default_conf.udp4.x -#define UD6(x) udp6_default_conf.udp6.x static char * usage_str = \ "Usage: irm ipcp bootstrap\n" " name <ipcp name>\n" " layer <layer name>\n" " [type [TYPE]]\n" - "where TYPE in {" UNICAST " " BROADCAST " " LOCAL " " - IP_UDP4 " " IP_UDP6 " " ETH_LLC " " ETH_DIX "},\n\n" + "where TYPE in {" UNICAST " " BROADCAST " " LOCAL "},\n\n" "if TYPE == " UNICAST "\n" " [addr_auth <ADDRESS_POLICY> (default: %s)]\n" " [directory <DIRECTORY_POLICY> (default: %s)]\n" @@ -117,28 +108,6 @@ static char * usage_str = \ " [ls_t_recalc <pff recalc interval (s)> (default: %ld)]\n" " [ls_t_update <LSA update interval (s)> (default: %ld)]\n" " [ls_t_timeo <link timeout (s)> (default: %ld)]\n\n" - "if TYPE == " IP_UDP4 "\n" - " ip <IP address in dotted notation>\n" - " [port <UDP port> (default: %d)]\n" - " [dns <DDNS IPv4 address in dotted notation>" - " (default: none)]\n\n" - "if TYPE == " IP_UDP6 "\n" - " ip <IPv6 address>\n" - " [port <UDP port> (default: %d)]\n" - " [dns <DDNS IPv6 address>" - " (default: none)]\n\n" - - "if TYPE == " ETH_LLC "\n" - " dev <interface name>\n" - " [hash [ALGORITHM] (default: %s)]\n" - "where ALGORITHM in {" SHA3_224 " " SHA3_256 " " - SHA3_384 " " SHA3_512 "}\n\n" - "if TYPE == " ETH_DIX "\n" - " dev <interface name>\n" - " [ethertype <ethertype> (default: 0x%4X)]\n" - " [hash [ALGORITHM] (default: %s)]\n" - "where ALGORITHM in {" SHA3_224 " " SHA3_256 " " - SHA3_384 " " SHA3_512 "}\n\n" "if TYPE == " LOCAL "\n" " [hash [ALGORITHM] (default: %s)]\n" "where ALGORITHM in {" SHA3_224 " " SHA3_256 " " @@ -160,15 +129,6 @@ static void usage(void) /* ls */ default_ls_config.t_recalc, default_ls_config.t_update, default_ls_config.t_timeo, - /* udp4 */ - UD4(port), - /* udp6 */ - UD6(port), - /* eth_llc */ - SHA3_256, - /* eth_dix */ - DIX(ethertype), - SHA3_256, /* local */ SHA3_256, /* broadcast */ @@ -190,19 +150,9 @@ int do_bootstrap_ipcp(int argc, enum pol_addr_auth addr_auth_type = UNI(addr_auth_type); enum pol_cong_avoid cong_avoid = UNI(cong_avoid); enum pol_dir_hash hash_algo = DIR_HASH_SHA3_256; - char * ipstr = NULL; - char * dnsstr = NULL; - struct in_addr ip4_addr = {.s_addr = INADDR_ANY}; - struct in_addr dns4_addr = UD4(dns_addr); - int port4 = UD4(port); - struct in6_addr ip6_addr = IN6ADDR_ANY_INIT; - struct in6_addr dns6_addr = UD6(dns_addr); - int port6 = UD6(port); char * ipcp_type = NULL; enum ipcp_type type = IPCP_INVALID; char * layer = NULL; - char * dev = NULL; - uint16_t ethertype = DIX(ethertype); struct ipcp_list_info * ipcps; ssize_t len = 0; int i = 0; @@ -211,6 +161,14 @@ int do_bootstrap_ipcp(int argc, while (argc > 0) { cargs = 2; + if (matches(*argv, "autobind") == 0) + cargs = 1; + + if (argc < cargs) { + usage(); + return -1; + } + if (matches(*argv, "type") == 0) { ipcp_type = *(argv + 1); } else if (matches(*argv, "layer") == 0) { @@ -228,24 +186,6 @@ int do_bootstrap_ipcp(int argc, hash_algo = DIR_HASH_SHA3_512; else goto unknown_param; - } else if (matches(*argv, "ip") == 0) { - ipstr = *(argv + 1); - } else if (matches(*argv, "dns") == 0) { - dnsstr = *(argv + 1); - } else if (matches(*argv, "device") == 0) { - dev = *(argv + 1); - } else if (matches(*argv, "ethertype") == 0) { - /* NOTE: We might do some more checks on strtol. */ - if (matches(*(argv + 1), "0x") == 0) - ethertype = strtol(*(argv + 1), NULL, 0); - else - ethertype = strtol(*(argv + 1), NULL, 16); - if (ethertype < 0x0600 || ethertype >= 0xFFFF) { - printf("Invalid Ethertype: \"%s\".\n" - "Recommended range: 0xA000-0xEFFF.\n", - *(argv + 1)); - return -1; - } } else if (matches(*argv, "addr") == 0) { addr_size = atoi(*(argv + 1)); } else if (matches(*argv, "eid") == 0) { @@ -254,9 +194,6 @@ int do_bootstrap_ipcp(int argc, max_ttl = atoi(*(argv + 1)); } else if (matches(*argv, "rtt") == 0) { max_rtt = atoi(*(argv + 1)); - } else if (matches(*argv, "port") == 0) { - port4 = atoi(*(argv + 1)); - port6 = port4; } else if (matches(*argv, "autobind") == 0) { autobind = true; cargs = 1; @@ -334,55 +271,11 @@ int do_bootstrap_ipcp(int argc, type = IPCP_UNICAST; else if (matches(ipcp_type, BROADCAST) == 0) type = IPCP_BROADCAST; - else if (matches(ipcp_type, IP_UDP4) == 0) - type = IPCP_UDP4; - else if (matches(ipcp_type, IP_UDP6) == 0) - type = IPCP_UDP6; - else if (matches(ipcp_type, ETH_DIX) == 0) - type = IPCP_ETH_DIX; - else if (matches(ipcp_type, ETH_LLC) == 0) - type = IPCP_ETH_LLC; else if (matches(ipcp_type, LOCAL) == 0) type = IPCP_LOCAL; else goto fail_usage; } - if (type == IPCP_UDP4) { - if (inet_pton (AF_INET, ipstr, &ip4_addr) != 1) { - printf("Invalid IPv4 address: \"%s\".\n", ipstr); - goto fail_usage; - } - - if (ip4_addr.s_addr == INADDR_ANY) { - printf("Cannot use IPv4 address: \"%s\".\n", ipstr); - goto fail_usage; - } - - if (dnsstr != NULL && - inet_pton(AF_INET, dnsstr, &dns4_addr) != 1) { - printf("Invalid DNS IPv4 address: \"%s\".\n", dnsstr); - goto fail_usage; - } - } - - if (type == IPCP_UDP6) { - if (inet_pton(AF_INET6, ipstr, &ip6_addr) != 1) { - printf("Invalid IPv6 address: \"%s\".\n", ipstr); - goto fail_usage; - } - - if (IN6_IS_ADDR_UNSPECIFIED(&ip6_addr)) { - printf("Cannot use IPv6 address: \"%s\".\n", ipstr); - goto fail_usage; - } - - if (dnsstr != NULL && - inet_pton(AF_INET6, dnsstr, &dns6_addr) != 1) { - printf("Invalid DNS IPv6 address: \"%s\".\n", dnsstr); - goto fail_usage; - } - } - if (pid == -1) { if (ipcp_type == NULL) { printf("No IPCPs matching %s found.\n\n", ipcp); @@ -432,29 +325,6 @@ int do_bootstrap_ipcp(int argc, conf.unicast.cong_avoid = cong_avoid; conf.unicast.dir = dir_config; break; - case IPCP_UDP4: - conf.udp4.ip_addr = ip4_addr; - conf.udp4.dns_addr = dns4_addr; - conf.udp4.port = port4; - break; - case IPCP_UDP6: - conf.udp6.ip_addr = ip6_addr; - conf.udp6.dns_addr = dns6_addr; - conf.udp6.port = port6; - break; - case IPCP_ETH_DIX: - conf.eth.ethertype = ethertype; - /* FALLTHRU */ - case IPCP_ETH_LLC: - if (dev == NULL) - goto fail_usage; - 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 */ case IPCP_LOCAL: diff --git a/src/tools/irm/irm_ipcp_connect.c b/src/tools/irm/irm_ipcp_connect.c index fb21faec..66646e7d 100644 --- a/src/tools/irm/irm_ipcp_connect.c +++ b/src/tools/irm/irm_ipcp_connect.c @@ -44,6 +44,7 @@ #include <stdio.h> #include <stdlib.h> +#include <arpa/inet.h> #include <string.h> #define DT "dt" @@ -55,10 +56,14 @@ static void usage(void) " name <ipcp name>\n" " dst <name of destination IPCP>\n" " [component [COMPONENT]]\n" - "where COMPONENT in {" DT " " MGMT "}\n\n" + " [udp [UDP_PEER]]\n" + " [eth [dev <device>]" + " [ethertype <ethertype>]]\n" + "where COMPONENT in {" DT " " MGMT "}\n" + "and UDP_PEER is <IP address or host>[:<port>]\n\n" "if COMPONENT == " DT "\n" - " [qos [QOS]\n" - "where QOS in {raw, best, voice, video, data}\n"); + " [qos [QOS]]\n" + "where QOS in {raw, safe, rt, rt-safe, msg}\n"); } int do_connect_ipcp(int argc, @@ -69,13 +74,29 @@ int do_connect_ipcp(int argc, char * comp = "*"; char * component = NULL; char * qos = NULL; + char * udpstr = NULL; + char * devstr = NULL; + uint16_t ethertype = POA_ETHERTYPE; + bool eth = false; + struct poa_addr addr; + struct poa_addr * pa = NULL; struct ipcp_list_info * ipcps; ssize_t len = 0; pid_t pid = -1; ssize_t i; + int cargs; qosspec_t qs = qos_raw; while (argc > 0) { + cargs = 2; + if (strcmp(*argv, "eth") == 0) + cargs = 1; + + if (argc < cargs) { + usage(); + return -1; + } + if (matches(*argv, "name") == 0) { ipcp = *(argv + 1); } else if (matches(*argv, "dst") == 0) { @@ -84,21 +105,66 @@ int do_connect_ipcp(int argc, comp = *(argv + 1); } else if (matches(*argv, "qos") == 0) { qos = *(argv + 1); + } else if (strcmp(*argv, "udp") == 0) { + udpstr = *(argv + 1); + } else if (strcmp(*argv, "dev") == 0) { + devstr = *(argv + 1); + } else if (strcmp(*argv, "ethertype") == 0) { + if (parse_ethertype(*(argv + 1), ðertype) < 0) { + printf("Invalid ethertype: \"%s\".\n", + *(argv + 1)); + return -1; + } + } else if (strcmp(*argv, "eth") == 0) { + eth = true; + cargs = 1; } else { printf("\"%s\" is unknown, try \"irm " "ipcp connect\".\n", *argv); return -1; } - argc -= 2; - argv += 2; + argc -= cargs; + argv += cargs; } - if (ipcp == NULL || dst == NULL || comp == NULL) { + if (ipcp == NULL || comp == NULL) { usage(); return -1; } + memset(&addr, 0, sizeof(addr)); + + if (udpstr != NULL) { + if (poa_addr_set_udp(&addr, udpstr) < 0) + return -1; + pa = &addr; + } + + if (eth) { + if (udpstr != NULL) { + printf("Connect via udp or eth, not both.\n"); + return -1; + } + + if (dst == NULL) { + usage(); + return -1; + } + + if (poa_addr_set_eth(&addr, devstr, ethertype) < 0) + return -1; + pa = &addr; + } + + if (dst == NULL && pa == NULL) { + usage(); + return -1; + } + + if (dst == NULL) + dst = ""; + if (qos != NULL) { if (strcmp(qos, "raw") == 0) qs = qos_raw; @@ -110,9 +176,11 @@ int do_connect_ipcp(int argc, qs = qos_rt_safe; else if (strcmp(qos, "msg") == 0) qs = qos_msg; - else if (strcmp(qos, "stream") == 0) - qs = qos_stream; - else + else if (strcmp(qos, "stream") == 0) { + printf("Stream QoS is not allowed on " + "IPCP component flows.\n"); + return -1; + } else printf("Unknown QoS cube, defaulting to raw.\n"); } @@ -129,13 +197,13 @@ int do_connect_ipcp(int argc, if (wildcard_match(comp, MGMT) == 0) { component = MGMT_COMP; /* FIXME: move to qos_msg when stable */ - if (irm_connect_ipcp(pid, dst, component, qos_raw)) + if (irm_connect_ipcp(pid, dst, component, qos_raw, pa)) return -1; } if (wildcard_match(comp, DT) == 0) { component = DT_COMP; - if (irm_connect_ipcp(pid, dst, component, qs)) + if (irm_connect_ipcp(pid, dst, component, qs, pa)) return -1; } diff --git a/src/tools/irm/irm_ipcp_create.c b/src/tools/irm/irm_ipcp_create.c index c6b2074b..15cfedde 100644 --- a/src/tools/irm/irm_ipcp_create.c +++ b/src/tools/irm/irm_ipcp_create.c @@ -46,10 +46,6 @@ #define UNICAST "unicast" #define BROADCAST "broadcast" -#define UDP4 "udp4" -#define UDP6 "udp6" -#define ETH_LLC "eth-llc" -#define ETH_DIX "eth-dix" #define LOCAL "local" static void usage(void) @@ -57,8 +53,7 @@ static void usage(void) printf("Usage: irm ipcp create\n" " name <ipcp name>\n" " type [TYPE]\n\n" - "where TYPE in {" UNICAST " " BROADCAST " " LOCAL " " - UDP4 " " UDP6 " " ETH_LLC " " ETH_DIX "}\n"); + "where TYPE in {" UNICAST " " BROADCAST " " LOCAL "}\n"); } int do_create_ipcp(int argc, @@ -93,16 +88,8 @@ int do_create_ipcp(int argc, type = IPCP_UNICAST; else if (strcmp(ipcp_type, BROADCAST) == 0) type = IPCP_BROADCAST; - else if (strcmp(ipcp_type, UDP4) == 0) - type = IPCP_UDP4; - else if (strcmp(ipcp_type, UDP6) == 0) - type = IPCP_UDP6; else if (strcmp(ipcp_type, LOCAL) == 0) type = IPCP_LOCAL; - else if (strcmp(ipcp_type, ETH_LLC) == 0) - type = IPCP_ETH_LLC; - else if (strcmp(ipcp_type, ETH_DIX) == 0) - type = IPCP_ETH_DIX; else { printf("IPCP type \"%s\" is unknown.\n", ipcp_type); usage(); diff --git a/src/tools/irm/irm_ipcp_enroll.c b/src/tools/irm/irm_ipcp_enroll.c index 350b536e..54fed022 100644 --- a/src/tools/irm/irm_ipcp_enroll.c +++ b/src/tools/irm/irm_ipcp_enroll.c @@ -44,6 +44,7 @@ #include "irm_ops.h" #include "irm_utils.h" +#include <arpa/inet.h> #include <string.h> #define UNICAST "unicast" @@ -57,7 +58,10 @@ static void usage(void) " [dst <destination to enroll with>]\n" " [type [TYPE], default = " UNICAST "]\n" " [autobind]\n" - "where TYPE in {" UNICAST " " BROADCAST "}\n"); + " [udp [UDP_PEER]]\n" + " [eth [dev <device>] [ethertype <ethertype>]]\n" + "where TYPE in {" UNICAST " " BROADCAST "}\n" + "and UDP_PEER is <IP address or host>[:<port>]\n"); } static int get_layer_name(const char * ipcp, @@ -86,6 +90,12 @@ int do_enroll_ipcp(int argc, char * ipcp = NULL; char * layer = NULL; char * dst = NULL; + char * udpstr = NULL; + char * devstr = NULL; + uint16_t ethertype = POA_ETHERTYPE; + bool eth = false; + struct poa_addr addr; + struct poa_addr * pa = NULL; struct ipcp_list_info * ipcps; pid_t pid = -1; ssize_t len = 0; @@ -97,14 +107,37 @@ int do_enroll_ipcp(int argc, while (argc > 0) { cargs = 2; + if (strcmp(*argv, "eth") == 0) + cargs = 1; + else if (matches(*argv, "autobind") == 0) + cargs = 1; + + if (argc < cargs) { + usage(); + return -1; + } + if (matches(*argv, "name") == 0) { ipcp = *(argv + 1); } else if (matches(*argv, "type") == 0) { ipcp_type = *(argv + 1); } else if (matches(*argv, "layer") == 0) { layer = *(argv + 1); - } else if (matches(*argv, "dst") == 0) { + } else if (strcmp(*argv, "dst") == 0) { dst = *(argv + 1); + } else if (strcmp(*argv, "udp") == 0) { + udpstr = *(argv + 1); + } else if (strcmp(*argv, "dev") == 0) { + devstr = *(argv + 1); + } else if (strcmp(*argv, "ethertype") == 0) { + if (parse_ethertype(*(argv + 1), ðertype) < 0) { + printf("Invalid ethertype: \"%s\".\n", + *(argv + 1)); + return -1; + } + } else if (strcmp(*argv, "eth") == 0) { + eth = true; + cargs = 1; } else if (matches(*argv, "autobind") == 0) { autobind = true; cargs = 1; @@ -126,6 +159,25 @@ int do_enroll_ipcp(int argc, if (dst == NULL) dst = layer; + memset(&addr, 0, sizeof(addr)); + + if (udpstr != NULL) { + if (poa_addr_set_udp(&addr, udpstr) < 0) + return -1; + pa = &addr; + } + + if (eth) { + if (udpstr != NULL) { + printf("Enroll via udp or eth, not both.\n"); + return -1; + } + + if (poa_addr_set_eth(&addr, devstr, ethertype) < 0) + return -1; + pa = &addr; + } + if (strcmp(ipcp_type, UNICAST) == 0) type = IPCP_UNICAST; else if (strcmp(ipcp_type, BROADCAST) == 0) @@ -155,7 +207,7 @@ int do_enroll_ipcp(int argc, pid = ipcps[i].pid; - if (irm_enroll_ipcp(pid, dst)) { + if (irm_enroll_ipcp(pid, dst, pa) < 0) { printf("Failed to enroll IPCP.\n"); goto fail; } diff --git a/src/tools/irm/irm_ipcp_list.c b/src/tools/irm/irm_ipcp_list.c index a211a02b..60154efb 100644 --- a/src/tools/irm/irm_ipcp_list.c +++ b/src/tools/irm/irm_ipcp_list.c @@ -48,10 +48,6 @@ #define UNICAST "unicast" #define BROADCAST "broadcast" -#define UDP4 "udp4" -#define UDP6 "udp6" -#define ETH_LLC "eth-llc" -#define ETH_DIX "eth-dix" #define LOCAL "local" static void usage(void) @@ -60,8 +56,7 @@ static void usage(void) " [name <ipcp name>]\n" " [layer <layer_name>]\n\n" " [type [TYPE]]\n\n" - "where TYPE = {" UNICAST " " LOCAL " " - UDP4 " " UDP6 " " ETH_LLC " " ETH_DIX "}\n"); + "where TYPE = {" UNICAST " " BROADCAST " " LOCAL "}\n"); } static char * str_type(enum ipcp_type type) @@ -71,14 +66,6 @@ static char * str_type(enum ipcp_type type) return UNICAST; case IPCP_BROADCAST: return BROADCAST; - case IPCP_ETH_LLC: - return ETH_LLC; - case IPCP_ETH_DIX: - return ETH_DIX; - case IPCP_UDP4: - return UDP4; - case IPCP_UDP6: - return UDP6; case IPCP_LOCAL: return LOCAL; default: @@ -116,16 +103,8 @@ int do_list_ipcp(int argc, type = IPCP_UNICAST; else if (strcmp(ipcp_type, BROADCAST) == 0) type = IPCP_BROADCAST; - else if (strcmp(ipcp_type, UDP4) == 0) - type = IPCP_UDP4; - else if (strcmp(ipcp_type, UDP6) == 0) - type = IPCP_UDP6; else if (strcmp(ipcp_type, LOCAL) == 0) type = IPCP_LOCAL; - else if (strcmp(ipcp_type, ETH_LLC) == 0) - type = IPCP_ETH_LLC; - else if (strcmp(ipcp_type, ETH_DIX) == 0) - type = IPCP_ETH_DIX; else { usage(); return -1; diff --git a/src/tools/irm/irm_ipcp_poa.c b/src/tools/irm/irm_ipcp_poa.c new file mode 100644 index 00000000..cd939020 --- /dev/null +++ b/src/tools/irm/irm_ipcp_poa.c @@ -0,0 +1,98 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * Connect components of unicast or broadcast IPC processes + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "irm_ops.h" +#include "irm_utils.h" + +#include <stdio.h> +#include <string.h> + +static void usage(void) +{ + printf("Usage: irm ipcp poa [OPERATION]\n\n" + "where OPERATION in {attach detach list help}\n"); +} + +static int do_help(int argc, + char ** argv) +{ + (void) argc; + (void) argv; + + usage(); + + return 0; +} + +static const struct cmd { + const char * cmd; + int (* func)(int argc, char ** argv); +} cmds[] = { + { "attach", do_attach_ipcp }, + { "detach", do_detach_ipcp }, + { "list", do_list_poas }, + { "help", do_help }, + { NULL, NULL } +}; + +static int do_cmd(const char * argv0, + int argc, + char ** argv) +{ + const struct cmd * c; + + for (c = cmds; c->cmd != NULL; ++c) + if (matches(argv0, c->cmd) == 0) + return c->func(argc - 1, argv + 1); + + fprintf(stderr, "\"%s\" is unknown, try \"irm ipcp poa help\".\n", + argv0); + + return -1; +} + +int poa_cmd(int argc, + char ** argv) +{ + if (argc < 1) { + usage(); + return -1; + } + + return do_cmd(argv[0], argc, argv); +} diff --git a/src/tools/irm/irm_ipcp_poa_attach.c b/src/tools/irm/irm_ipcp_poa_attach.c new file mode 100644 index 00000000..74a83344 --- /dev/null +++ b/src/tools/irm/irm_ipcp_poa_attach.c @@ -0,0 +1,153 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * Connect components of unicast or broadcast IPC processes + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <ouroboros/irm.h> + +#include "irm_ops.h" +#include "irm_utils.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void usage(void) +{ + printf("Usage: irm ipcp poa attach\n" + " name <ipcp name>\n" + " [udp [UDP_POA]]\n" + " [eth [ETH_POA]]\n" + "where exactly one of udp or eth is given\n" + "and UDP_POA is <local IP address>[:<port>]\n" + "and ETH_POA is dev <device> [ethertype <ethertype>]\n"); +} + +int do_attach_ipcp(int argc, + char ** argv) +{ + char * ipcp = NULL; + char * udpstr = NULL; + char * devstr = NULL; + uint16_t ethertype = POA_ETHERTYPE; + bool eth = false; + struct poa_spec poa; + char str[POA_STRLEN + 1]; + struct ipcp_list_info * ipcps; + ssize_t len = 0; + pid_t pid = -1; + ssize_t i; + int cargs; + + while (argc > 0) { + cargs = 2; + + if (strcmp(*argv, "eth") == 0) + cargs = 1; + + if (argc < cargs) { + usage(); + return -1; + } + + if (matches(*argv, "name") == 0) { + ipcp = *(argv + 1); + } else if (strcmp(*argv, "udp") == 0) { + udpstr = *(argv + 1); + } else if (strcmp(*argv, "dev") == 0) { + devstr = *(argv + 1); + } else if (strcmp(*argv, "ethertype") == 0) { + if (parse_ethertype(*(argv + 1), ðertype) < 0) { + printf("Invalid ethertype: \"%s\".\n", + *(argv + 1)); + return -1; + } + } else if (strcmp(*argv, "eth") == 0) { + eth = true; + cargs = 1; + } else { + printf("\"%s\" is unknown, try \"irm ipcp " + "poa attach\".\n", *argv); + return -1; + } + + argc -= cargs; + argv += cargs; + } + + if (ipcp == NULL) { + usage(); + return -1; + } + + if (eth && udpstr != NULL) { + printf("A PoA is udp or eth, not both.\n"); + return -1; + } + + if (eth && devstr == NULL) { + printf("An eth PoA needs a device.\n"); + return -1; + } + + if (!eth && udpstr == NULL) { + usage(); + return -1; + } + + if (poa_spec_set(&poa, udpstr, devstr, ethertype) < 0) + return -1; + + len = irm_list_ipcps(&ipcps); + for (i = 0; i < len; i++) + if (strcmp(ipcps[i].name, ipcp) == 0) + pid = ipcps[i].pid; + + free(ipcps); + + if (pid == -1) { + printf("No such IPCP: \"%s\".\n", ipcp); + return -1; + } + + if (irm_attach_ipcp(pid, &poa) < 0) { + poa_spec_str(&poa, str, sizeof(str)); + printf("Failed to attach PoA %s on IPCP %s.\n", str, ipcp); + return -1; + } + + return 0; +} diff --git a/src/tools/irm/irm_ipcp_poa_detach.c b/src/tools/irm/irm_ipcp_poa_detach.c new file mode 100644 index 00000000..ce6bef13 --- /dev/null +++ b/src/tools/irm/irm_ipcp_poa_detach.c @@ -0,0 +1,153 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * Connect components of unicast or broadcast IPC processes + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <ouroboros/irm.h> + +#include "irm_ops.h" +#include "irm_utils.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void usage(void) +{ + printf("Usage: irm ipcp poa detach\n" + " name <ipcp name>\n" + " [udp [UDP_POA]]\n" + " [eth [ETH_POA]]\n" + "where exactly one of udp or eth is given\n" + "and UDP_POA is <local IP address>[:<port>]\n" + "and ETH_POA is dev <device> [ethertype <ethertype>]\n"); +} + +int do_detach_ipcp(int argc, + char ** argv) +{ + char * ipcp = NULL; + char * udpstr = NULL; + char * devstr = NULL; + uint16_t ethertype = POA_ETHERTYPE; + bool eth = false; + struct poa_spec poa; + char str[POA_STRLEN + 1]; + struct ipcp_list_info * ipcps; + ssize_t len = 0; + pid_t pid = -1; + ssize_t i; + int cargs; + + while (argc > 0) { + cargs = 2; + + if (strcmp(*argv, "eth") == 0) + cargs = 1; + + if (argc < cargs) { + usage(); + return -1; + } + + if (matches(*argv, "name") == 0) { + ipcp = *(argv + 1); + } else if (strcmp(*argv, "udp") == 0) { + udpstr = *(argv + 1); + } else if (strcmp(*argv, "dev") == 0) { + devstr = *(argv + 1); + } else if (strcmp(*argv, "ethertype") == 0) { + if (parse_ethertype(*(argv + 1), ðertype) < 0) { + printf("Invalid ethertype: \"%s\".\n", + *(argv + 1)); + return -1; + } + } else if (strcmp(*argv, "eth") == 0) { + eth = true; + cargs = 1; + } else { + printf("\"%s\" is unknown, try \"irm ipcp " + "poa detach\".\n", *argv); + return -1; + } + + argc -= cargs; + argv += cargs; + } + + if (ipcp == NULL) { + usage(); + return -1; + } + + if (eth && udpstr != NULL) { + printf("A PoA is udp or eth, not both.\n"); + return -1; + } + + if (eth && devstr == NULL) { + printf("An eth PoA needs a device.\n"); + return -1; + } + + if (!eth && udpstr == NULL) { + usage(); + return -1; + } + + if (poa_spec_set(&poa, udpstr, devstr, ethertype) < 0) + return -1; + + len = irm_list_ipcps(&ipcps); + for (i = 0; i < len; i++) + if (strcmp(ipcps[i].name, ipcp) == 0) + pid = ipcps[i].pid; + + free(ipcps); + + if (pid == -1) { + printf("No such IPCP: \"%s\".\n", ipcp); + return -1; + } + + if (irm_detach_ipcp(pid, &poa) < 0) { + poa_spec_str(&poa, str, sizeof(str)); + printf("Failed to detach PoA %s on IPCP %s.\n", str, ipcp); + return -1; + } + + return 0; +} diff --git a/src/tools/irm/irm_ipcp_poa_list.c b/src/tools/irm/irm_ipcp_poa_list.c new file mode 100644 index 00000000..8797c3c1 --- /dev/null +++ b/src/tools/irm/irm_ipcp_poa_list.c @@ -0,0 +1,136 @@ +/* + * Ouroboros - Copyright (C) 2016 - 2026 + * + * List the points of attachment of an IPC process + * + * Dimitri Staessens <dimitri@ouroboros.rocks> + * Sander Vrijders <sander@ouroboros.rocks> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <ouroboros/irm.h> + +#include "irm_ops.h" +#include "irm_utils.h" + +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void usage(void) +{ + printf("Usage: irm ipcp poa list\n" + " name <ipcp name>\n"); +} + +static void print_poa(const struct poa_spec * poa) +{ + char buf[INET6_ADDRSTRLEN]; + + switch (poa->type) { + case POA_UDP4: + if (inet_ntop(AF_INET, &poa->udp4.ip_addr, buf, + sizeof(buf)) == NULL) + return; + printf("%-6s %s:%u\n", "udp4", buf, poa->udp4.port); + break; + case POA_UDP6: + if (inet_ntop(AF_INET6, &poa->udp6.ip_addr, buf, + sizeof(buf)) == NULL) + return; + printf("%-6s [%s]:%u\n", "udp6", buf, poa->udp6.port); + break; + case POA_ETH: + printf("%-6s %s 0x%04X %02x:%02x:%02x:%02x:%02x:%02x\n", + "eth", poa->eth.dev, poa->eth.ethertype, + poa->eth.mac[0], poa->eth.mac[1], poa->eth.mac[2], + poa->eth.mac[3], poa->eth.mac[4], poa->eth.mac[5]); + break; + default: + break; + } +} + +int do_list_poas(int argc, + char ** argv) +{ + char * ipcp = NULL; + struct poa_spec * poas = NULL; + struct ipcp_list_info * ipcps; + ssize_t len = 0; + pid_t pid = -1; + ssize_t n; + ssize_t i; + + while (argc > 1) { + if (matches(*argv, "name") == 0) { + ipcp = *(argv + 1); + } else { + printf("\"%s\" is unknown, try \"irm ipcp " + "poa list\".\n", *argv); + return -1; + } + + argc -= 2; + argv += 2; + } + + if (ipcp == NULL) { + usage(); + return -1; + } + + len = irm_list_ipcps(&ipcps); + for (i = 0; i < len; i++) + if (strcmp(ipcps[i].name, ipcp) == 0) + pid = ipcps[i].pid; + + free(ipcps); + + if (pid == -1) { + printf("No such IPCP: \"%s\".\n", ipcp); + return -1; + } + + n = irm_list_poas(pid, &poas); + if (n < 0) { + printf("Failed to list PoAs of %s.\n", ipcp); + return -1; + } + + for (i = 0; i < n; i++) + print_poa(&poas[i]); + + free(poas); + + return 0; +} diff --git a/src/tools/irm/irm_name_create.c b/src/tools/irm/irm_name_create.c index 40a51193..034b4c99 100644 --- a/src/tools/irm/irm_name_create.c +++ b/src/tools/irm/irm_name_create.c @@ -117,6 +117,11 @@ int do_create_name(int argc, --argc; while (argc > 0) { + if (argc < 2) { + usage(); + return -1; + } + if (matches(*argv, "lb") == 0) { lb_pol = *(argv + 1); } else if (matches(*argv, "ssecpath") == 0) { diff --git a/src/tools/irm/irm_name_list.c b/src/tools/irm/irm_name_list.c index 37e1f023..a5a33073 100644 --- a/src/tools/irm/irm_name_list.c +++ b/src/tools/irm/irm_name_list.c @@ -49,6 +49,12 @@ #define RR "round-robin" #define SPILL "spillover" +static void usage(void) +{ + printf("Usage: irm name list\n" + " [name <name>]\n"); +} + static char * str_pol(enum pol_balance p) { switch(p) { @@ -70,7 +76,12 @@ int do_list_name(int argc, ssize_t i; while (argc > 0) { - if (matches(*argv, "list") == 0) { + if (argc < 2) { + usage(); + return -1; + } + + if (matches(*argv, "name") == 0) { name = *(argv + 1); } else { printf("\"%s\" is unknown, try \"irm " diff --git a/src/tools/irm/irm_name_reg.c b/src/tools/irm/irm_name_reg.c index 860f4a70..25e9fbb8 100644 --- a/src/tools/irm/irm_name_reg.c +++ b/src/tools/irm/irm_name_reg.c @@ -80,6 +80,11 @@ int do_reg_name(int argc, --argc; while (argc > 0) { + if (argc < 2) { + usage(); + return -1; + } + if (matches(*argv, "layer") == 0) { layers[layers_len++] = *(argv + 1); if (layers_len > MAX_LAYERS) { diff --git a/src/tools/irm/irm_name_unreg.c b/src/tools/irm/irm_name_unreg.c index abf08548..1b2cf29c 100644 --- a/src/tools/irm/irm_name_unreg.c +++ b/src/tools/irm/irm_name_unreg.c @@ -76,6 +76,11 @@ int do_unreg_name(int argc, --argc; while (argc > 0) { + if (argc < 2) { + usage(); + return -1; + } + if (matches(*argv, "layer") == 0) { layers[layers_len++] = *(argv + 1); if (layers_len > MAX_LAYERS) { diff --git a/src/tools/irm/irm_ops.h b/src/tools/irm/irm_ops.h index 195c5cbc..7f6c65cd 100644 --- a/src/tools/irm/irm_ops.h +++ b/src/tools/irm/irm_ops.h @@ -51,6 +51,18 @@ int do_bootstrap_ipcp(int argc, int do_enroll_ipcp(int argc, char ** argv); +int poa_cmd(int argc, + char ** argv); + +int do_attach_ipcp(int argc, + char ** argv); + +int do_detach_ipcp(int argc, + char ** argv); + +int do_list_poas(int argc, + char ** argv); + int do_connect_ipcp(int argc, char ** argv); diff --git a/src/tools/irm/irm_unbind.c b/src/tools/irm/irm_unbind.c index 4e5914a9..f98d0931 100644 --- a/src/tools/irm/irm_unbind.c +++ b/src/tools/irm/irm_unbind.c @@ -78,8 +78,8 @@ static int do_cmd(const char * argv0, const struct cmd * c; for (c = cmds; c->cmd; ++c) - if (!matches(argv0, c->cmd)) - return c->func(argc, argv); + if (matches(argv0, c->cmd) == 0) + return c->func(argc - 1, argv + 1); fprintf(stderr, "\"%s\" is unknown, try \"irm unbind help\".\n", argv0); diff --git a/src/tools/irm/irm_unbind_ipcp.c b/src/tools/irm/irm_unbind_ipcp.c index 23e25057..5d78603d 100644 --- a/src/tools/irm/irm_unbind_ipcp.c +++ b/src/tools/irm/irm_unbind_ipcp.c @@ -63,15 +63,20 @@ int do_unbind_ipcp(int argc, ssize_t len; ssize_t i; + if (argc < 1) { + usage(); + return -1; + } + + ipcp = *argv; + ++argv; + --argc; + while (argc > 0) { if (matches(*argv, "name") == 0) { name = *(argv + 1); ++argv; --argc; - } else if (matches(*argv, "ipcp") == 0) { - ipcp = *(argv + 1); - ++argv; - --argc; } else { printf("\"%s\" is unknown, try \"irm " "unbind ipcp\".\n", *argv); diff --git a/src/tools/irm/irm_unbind_process.c b/src/tools/irm/irm_unbind_process.c index bc7e545c..dfa91f4b 100644 --- a/src/tools/irm/irm_unbind_process.c +++ b/src/tools/irm/irm_unbind_process.c @@ -58,15 +58,20 @@ int do_unbind_process(int argc, pid_t pid = -1; char * name = NULL; + if (argc < 1) { + usage(); + return -1; + } + + pid = strtol(*argv, NULL, 10); + ++argv; + --argc; + while (argc > 1) { if (matches(*argv, "name") == 0) { name = *(argv + 1); ++argv; --argc; - } else if (matches(*argv, "process") == 0) { - pid = strtol(*(argv + 1), NULL, 10); - ++argv; - --argc; } else { printf("\"%s\" is unknown, try \"irm " "unbind process\".\n", *argv); diff --git a/src/tools/irm/irm_unbind_program.c b/src/tools/irm/irm_unbind_program.c index 031b9909..4ee8ce24 100644 --- a/src/tools/irm/irm_unbind_program.c +++ b/src/tools/irm/irm_unbind_program.c @@ -57,15 +57,25 @@ int do_unbind_program(int argc, char * name = NULL; char * prog = NULL; + if (argc < 1) { + usage(); + return -1; + } + + prog = *argv; + ++argv; + --argc; + while (argc > 0) { + if (argc < 2) { + usage(); + return -1; + } + if (matches(*argv, "name") == 0) { name = *(argv + 1); ++argv; --argc; - } else if (matches(*argv, "program") == 0) { - prog = *(argv + 1); - ++argv; - --argc; } else { printf("\"%s\" is unknown, try \"irm " "unbind program\".\n", *argv); diff --git a/src/tools/irm/irm_utils.c b/src/tools/irm/irm_utils.c index 69873097..c43accec 100644 --- a/src/tools/irm/irm_utils.c +++ b/src/tools/irm/irm_utils.c @@ -77,10 +77,21 @@ */ -#include <string.h> +#if defined(__linux__) || defined(__CYGWIN__) +#define _DEFAULT_SOURCE +#else +#define _POSIX_C_SOURCE 200809L +#endif + +#include <ouroboros/ipcp.h> #include "irm_utils.h" +#include <arpa/inet.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + int matches(const char * cmd, const char * pattern) { @@ -123,3 +134,223 @@ int wildcard_match(const char * pattern, } } } + +/* Splits "<addr>[:<port>]"; bare IPv6 needs no brackets. */ +static int parse_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: + printf("Invalid UDP address: \"%s\".\n", str); + return -1; +} + +/* An unresolved name is left for the IRMd, which picks the family. */ +int poa_addr_set_udp(struct poa_addr * addr, + const char * str) +{ + char host[POA_HOST_STRLEN + 1]; + int port; + + if (parse_udp_str(str, host, &port) < 0) + return -1; + + 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; +} + +/* + * Parses a hex ethertype; rejects garbage and out-of-range values. + * Overflow clamps to LONG_MAX and lands in the range check. + */ +int parse_ethertype(const char * str, + uint16_t * ethertype) +{ + char * end; + long val; + + val = strtol(str, &end, 16); + + if (end == str || *end != '\0') + return -1; + + if (val < 0 || val > 0xFFFF) + return -1; + + *ethertype = (uint16_t) val; + + return 0; +} + +int poa_addr_set_eth(struct poa_addr * addr, + const char * devstr, + uint16_t ethertype) +{ + addr->type = POA_ETH; + + addr->eth.src.ethertype = ethertype; + addr->eth.dst.ethertype = ethertype; + + if (devstr != NULL) { + if (strlen(devstr) > DEV_NAME_SIZE) { + printf("Invalid device name: \"%s\".\n", devstr); + return -1; + } + + strcpy(addr->eth.src.dev, devstr); + } + + return 0; +} + +/* Matches src/ipcpd/ipcp.c; keep in sync. */ +void poa_spec_str(const struct poa_spec * poa, + char * buf, + size_t len) +{ + char addr[INET6_ADDRSTRLEN]; + + switch (poa->type) { + case POA_UDP4: + if (inet_ntop(AF_INET, &poa->udp4.ip_addr, + addr, sizeof(addr)) == NULL) + break; + + snprintf(buf, len, "udp4 %s:%u", addr, poa->udp4.port); + return; + case POA_UDP6: + if (inet_ntop(AF_INET6, &poa->udp6.ip_addr, + addr, sizeof(addr)) == NULL) + break; + + snprintf(buf, len, "udp6 [%s]:%u", addr, poa->udp6.port); + return; + case POA_ETH: + snprintf(buf, len, "eth %s 0x%04X", poa->eth.dev, + poa->eth.ethertype); + return; + default: + break; + } + + snprintf(buf, len, "(unknown)"); +} + +int poa_spec_set(struct poa_spec * poa, + const char * udpstr, + const char * devstr, + uint16_t ethertype) +{ + char host[POA_HOST_STRLEN + 1]; + int port; + + memset(poa, 0, sizeof(*poa)); + + if ((udpstr != NULL) + (devstr != NULL) > 1) { + printf("A PoA is an address or a device.\n"); + return -1; + } + + if (udpstr != NULL) { + if (parse_udp_str(udpstr, host, &port) < 0) + return -1; + + if (inet_pton(AF_INET, host, &poa->udp4.ip_addr) == 1) { + poa->type = POA_UDP4; + poa->udp4.port = port; + return 0; + } + + if (inet_pton(AF_INET6, host, &poa->udp6.ip_addr) == 1) { + poa->type = POA_UDP6; + poa->udp6.port = port; + return 0; + } + + printf("Invalid IP address: \"%s\".\n", udpstr); + return -1; + } + + if (devstr != NULL) { + if (strlen(devstr) > DEV_NAME_SIZE) { + printf("Invalid device name: \"%s\".\n", devstr); + return -1; + } + + poa->type = POA_ETH; + poa->eth.ethertype = ethertype; + + strcpy(poa->eth.dev, devstr); + + return 0; + } + + return -1; +} diff --git a/src/tools/irm/irm_utils.h b/src/tools/irm/irm_utils.h index c6d4bf18..3760b4e4 100644 --- a/src/tools/irm/irm_utils.h +++ b/src/tools/irm/irm_utils.h @@ -79,10 +79,43 @@ #ifndef OUROBOROS_TOOLS_IRM_UTILS_H #define OUROBOROS_TOOLS_IRM_UTILS_H -int matches(const char * cmd, - const char * pattern); +#include <ouroboros/ipcp.h> -int wildcard_match(const char * pattern, - const char * string); +#include <arpa/inet.h> + +#include <stdint.h> + +int matches(const char * cmd, + const char * pattern); + +int wildcard_match(const char * pattern, + const char * string); + +/* Fill one PoA to attach or detach: an address or a device. */ +int poa_spec_set(struct poa_spec * poa, + const char * udpstr, + const char * devstr, + uint16_t ethertype); + +/* Fill a peer PoA address; a host name is resolved by the IRMd. */ +int poa_addr_set_udp(struct poa_addr * addr, + const char * str); + +/* Fits "eth <dev> 0x<type>", the longest PoA rendering. */ +/* Matches src/ipcpd/ipcp.c; keep in sync. */ +#define POA_STRLEN (DEV_NAME_SIZE + 11) + +/* Names a PoA the way the IPCP logs it. */ +void poa_spec_str(const struct poa_spec * poa, + char * buf, + size_t len); + +int poa_addr_set_eth(struct poa_addr * addr, + const char * devstr, + uint16_t ethertype); + +/* Parses a hex ethertype; rejects garbage and out-of-range values. */ +int parse_ethertype(const char * str, + uint16_t * ethertype); #endif /* OUROBOROS_TOOLS_IRM_UTILS_H */ diff --git a/src/tools/ocbr/ocbr_client.c b/src/tools/ocbr/ocbr_client.c index 36c07d43..60d4a0fc 100644 --- a/src/tools/ocbr/ocbr_client.c +++ b/src/tools/ocbr/ocbr_client.c @@ -88,10 +88,12 @@ int client_main(char * server, struct timespec start; struct timespec end; struct timespec intv = {(gap / BILLION), gap % BILLION}; - int ms; - const char * qenv; - qosspec_t qs; - qosspec_t * qsp; + int ms; + ssize_t rc; + int werr = 0; + const char * qenv; + qosspec_t qs; + qosspec_t * qsp; qsp = NULL; @@ -147,7 +149,9 @@ int client_main(char * server, ts_add(&end, &intv, &end); memcpy(buf, &seqnr, sizeof(seqnr)); - if (flow_write(fd, buf, size) < 0) { + rc = flow_write(fd, buf, size); + if (rc < 0) { + werr = (int) rc; stop = true; continue; } @@ -165,7 +169,10 @@ int client_main(char * server, } else { /* flood */ while (!stop) { clock_gettime(CLOCK_REALTIME, &end); - if (flow_write(fd, buf, size) < 0) { + + rc = flow_write(fd, buf, size); + if (rc < 0) { + werr = (int) rc; stop = true; continue; } @@ -183,6 +190,10 @@ int client_main(char * server, ms = ts_diff_ms(&end, &start); + /* Codes at or above 1000 are ouroboros errno.h values. */ + if (werr != 0) + printf("Send ended on write error %d.\n", werr); + printf("sent statistics: " "%9ld packets, %12ld bytes in %9d ms, %4.4f Mb/s\n", seqnr, seqnr * size, ms, (seqnr / (ms * 1000.0)) * size * 8.0); diff --git a/src/tools/oftp/oftp.c b/src/tools/oftp/oftp.c index 2504393a..b66ef650 100644 --- a/src/tools/oftp/oftp.c +++ b/src/tools/oftp/oftp.c @@ -35,7 +35,12 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. */ +#if defined(__APPLE__) +/* macOS hides O_NOFOLLOW behind the BSD feature set. */ +#define _DARWIN_C_SOURCE +#else #define _POSIX_C_SOURCE 200809L +#endif #include <ouroboros/crc64.h> #include <ouroboros/dev.h> diff --git a/src/tools/oping/oping_client.c b/src/tools/oping/oping_client.c index 4b01315d..b60c73cb 100644 --- a/src/tools/oping/oping_client.c +++ b/src/tools/oping/oping_client.c @@ -193,8 +193,6 @@ void * writer(void * o) pthread_cleanup_push(free, buf); while (!stop && client.sent < client.count) { - nanosleep(&wait, NULL); - clock_gettime(CLOCK_MONOTONIC, &now); msg->type = htonl(ECHO_REQUEST); @@ -206,6 +204,8 @@ void * writer(void * o) printf("Failed to send packet.\n"); stop = true; } + + nanosleep(&wait, NULL); } pthread_cleanup_pop(true); |
