diff --git a/kronosnetd/cfg.c b/kronosnetd/cfg.c index 769a7b31..0260ec8e 100644 --- a/kronosnetd/cfg.c +++ b/kronosnetd/cfg.c @@ -1,64 +1,72 @@ #include "config.h" #include #include #include #include #include "cfg.h" #include "libtap.h" struct knet_cfg *knet_get_iface(const char *name, int create) { struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg; int found = 0; while (knet_iface != NULL) { if (!strcmp(tap_get_name(knet_iface->cfg_eth.tap), name)) { found = 1; break; } knet_iface = knet_iface->next; } if ((!found) && (create)) { knet_iface = malloc(sizeof(struct knet_cfg)); if (!knet_iface) goto out_clean; memset(knet_iface, 0, sizeof(struct knet_cfg)); knet_iface->cfg_ring.base_port = KNET_RING_DEFPORT; + strncpy(knet_iface->knet_handle_crypto_cfg.crypto_model, + "none", + sizeof(knet_iface->knet_handle_crypto_cfg.crypto_model) - 1); + + strncpy(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type, + "none", + sizeof(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type) - 1); + + strncpy(knet_iface->knet_handle_crypto_cfg.crypto_hash_type, + "none", + sizeof(knet_iface->knet_handle_crypto_cfg.crypto_hash_type) - 1); + knet_iface->next = knet_cfg_head.knet_cfg; knet_cfg_head.knet_cfg = knet_iface; } out_clean: return knet_iface; } void knet_destroy_iface(struct knet_cfg *knet_iface) { struct knet_cfg *knet_iface_tmp = knet_cfg_head.knet_cfg; struct knet_cfg *knet_iface_prev = knet_cfg_head.knet_cfg; while (knet_iface_tmp != knet_iface) { knet_iface_prev = knet_iface_tmp; knet_iface_tmp = knet_iface_tmp->next; } if (knet_iface_tmp == knet_iface) { if (knet_iface_tmp == knet_iface_prev) { knet_cfg_head.knet_cfg = knet_iface_tmp->next; } else { knet_iface_prev->next = knet_iface_tmp->next; } - if (knet_iface->crypto_method) - free(knet_iface->crypto_method); - if (knet_iface->hash_method) - free(knet_iface->hash_method); free(knet_iface); } } diff --git a/kronosnetd/cfg.h b/kronosnetd/cfg.h index e26b29d6..44243b3a 100644 --- a/kronosnetd/cfg.h +++ b/kronosnetd/cfg.h @@ -1,42 +1,41 @@ #ifndef __CFG_H__ #define __CFG_H__ #include #include #include "libtap.h" #include "libknet.h" struct knet_cfg_eth { tap_t tap; uint16_t node_id; }; struct knet_cfg_ring { knet_handle_t knet_h; int base_port; }; struct knet_cfg { struct knet_cfg_eth cfg_eth; struct knet_cfg_ring cfg_ring; int active; - char *crypto_method; - char *hash_method; + struct knet_handle_crypto_cfg knet_handle_crypto_cfg; struct knet_cfg *next; }; struct knet_cfg_top { char *conffile; char *logfile; char *vty_ip; char *vty_port; struct knet_cfg *knet_cfg; }; struct knet_cfg *knet_get_iface(const char *name, const int create); void knet_destroy_iface(struct knet_cfg *knet_iface); extern struct knet_cfg_top knet_cfg_head; #endif diff --git a/kronosnetd/vty_cli_cmds.c b/kronosnetd/vty_cli_cmds.c index f873638d..a3479f9e 100644 --- a/kronosnetd/vty_cli_cmds.c +++ b/kronosnetd/vty_cli_cmds.c @@ -1,1667 +1,1697 @@ #include "config.h" #include #include #include #include #include #include #include #include "cfg.h" #include "logging.h" #include "libtap.h" #include "netutils.h" #include "vty.h" #include "vty_cli.h" #include "vty_cli_cmds.h" #include "vty_utils.h" -#define KNET_VTY_MAX_MATCHES 64 -#define KNET_VTY_MATCH_HELP 0 -#define KNET_VTY_MATCH_EXEC 1 -#define KNET_VTY_MATCH_EXPAND 2 - -#define CMDS_PARAM_NOMORE 0 -#define CMDS_PARAM_KNET 1 -#define CMDS_PARAM_IP 2 -#define CMDS_PARAM_IP_PREFIX 3 -#define CMDS_PARAM_IP_PORT 4 -#define CMDS_PARAM_BOOL 5 -#define CMDS_PARAM_INT 6 -#define CMDS_PARAM_NODEID 7 -#define CMDS_PARAM_NAME 8 -#define CMDS_PARAM_MTU 9 -#define CMDS_PARAM_CRYPTO 10 -#define CMDS_PARAM_HASH 11 +#define KNET_VTY_MAX_MATCHES 64 +#define KNET_VTY_MATCH_HELP 0 +#define KNET_VTY_MATCH_EXEC 1 +#define KNET_VTY_MATCH_EXPAND 2 + +#define CMDS_PARAM_NOMORE 0 +#define CMDS_PARAM_KNET 1 +#define CMDS_PARAM_IP 2 +#define CMDS_PARAM_IP_PREFIX 3 +#define CMDS_PARAM_IP_PORT 4 +#define CMDS_PARAM_BOOL 5 +#define CMDS_PARAM_INT 6 +#define CMDS_PARAM_NODEID 7 +#define CMDS_PARAM_NAME 8 +#define CMDS_PARAM_MTU 9 +#define CMDS_PARAM_CRYPTO_MODEL 10 +#define CMDS_PARAM_CRYPTO_TYPE 11 +#define CMDS_PARAM_HASH_TYPE 12 /* * CLI helper functions - menu/node stuff starts below */ /* * return 0 if we find a command in vty->line and cmd/len/no are set * return -1 if we cannot find a command. no can be trusted. cmd/len would be empty */ static int get_command(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset, int *no) { int start = 0, idx; for (idx = 0; idx < vty->line_idx; idx++) { if (vty->line[idx] != ' ') break; } if (!strncmp(&vty->line[idx], "no ", 3)) { *no = 1; idx = idx + 3; for (idx = idx; idx < vty->line_idx; idx++) { if (vty->line[idx] != ' ') break; } } else { *no = 0; } start = idx; if (start == vty->line_idx) return -1; *cmd = &vty->line[start]; *cmdoffset = start; for (idx = start; idx < vty->line_idx; idx++) { if (vty->line[idx] == ' ') break; } *cmdlen = idx - start; return 0; } /* * still not sure why I need to count backwards... */ static void get_n_word_from_end(struct knet_vty *vty, int n, char **word, int *wlen, int *woffset) { int widx; int idx, end, start; start = end = vty->line_idx; for (widx = 0; widx < n; widx++) { for (idx = start - 1; idx > 0; idx--) { if (vty->line[idx] != ' ') break; } end = idx; for (idx = end; idx > 0; idx--) { if (vty->line[idx-1] == ' ') break; } start = idx; } *wlen = (end - start) + 1; *word = &vty->line[start]; *woffset = start; } static int expected_params(const vty_param_t *params) { int idx = 0; while(params[idx].param != CMDS_PARAM_NOMORE) idx++; return idx; } static int count_words(struct knet_vty *vty, int offset) { int idx, widx = 0; int status = 0; for (idx = offset; idx < vty->line_idx; idx++) { if (vty->line[idx] == ' ') { status = 0; continue; } if ((vty->line[idx] != ' ') && (!status)) { widx++; status = 1; continue; } } return widx; } static int param_to_int(const char *param, int paramlen) { char buf[KNET_VTY_MAX_LINE]; memset(buf, 0, sizeof(buf)); memcpy(buf, param, paramlen); return atoi(buf); } static int param_to_str(char *buf, int bufsize, const char *param, int paramlen) { if (bufsize < paramlen) return -1; memset(buf, 0, bufsize); memcpy(buf, param, paramlen); return paramlen; } static const vty_node_cmds_t *get_cmds(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset) { int no; const vty_node_cmds_t *cmds = knet_vty_nodes[vty->node].cmds; get_command(vty, cmd, cmdlen, cmdoffset, &no); if (no) cmds = knet_vty_nodes[vty->node].no_cmds; return cmds; } static int check_param(struct knet_vty *vty, const int paramtype, char *param, int paramlen) { int err = 0; char buf[KNET_VTY_MAX_LINE]; int tmp; memset(buf, 0, sizeof(buf)); switch(paramtype) { case CMDS_PARAM_NOMORE: break; case CMDS_PARAM_KNET: if (paramlen >= IFNAMSIZ) { knet_vty_write(vty, "interface name too long%s", telnet_newline); err = -1; } break; case CMDS_PARAM_IP: break; case CMDS_PARAM_IP_PREFIX: break; case CMDS_PARAM_IP_PORT: tmp = param_to_int(param, paramlen); if ((tmp < 0) || (tmp > 65279)) { knet_vty_write(vty, "port number must be a value between 0 and 65279%s", telnet_newline); err = -1; } break; case CMDS_PARAM_BOOL: break; case CMDS_PARAM_INT: break; case CMDS_PARAM_NODEID: tmp = param_to_int(param, paramlen); if ((tmp < 0) || (tmp > 255)) { knet_vty_write(vty, "node id must be a value between 0 and 255%s", telnet_newline); err = -1; } break; case CMDS_PARAM_NAME: if (paramlen >= KNET_MAX_HOST_LEN) { knet_vty_write(vty, "name cannot exceed %d char in len%s", KNET_MAX_HOST_LEN - 1, telnet_newline); } break; case CMDS_PARAM_MTU: tmp = param_to_int(param, paramlen); if ((tmp < 576) || (tmp > 65536)) { knet_vty_write(vty, "mtu should be a value between 576 and 65536 (note: max value depends on the media)%s", telnet_newline); err = -1; } break; - case CMDS_PARAM_CRYPTO: + case CMDS_PARAM_CRYPTO_MODEL: + param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); + if (!strncmp("none", buf, 4)) + break; + if (!strncmp("nss", buf, 3)) + break; + knet_vty_write(vty, "unknown encryption model: %s. Supported: none/nss%s", param, telnet_newline); + err = -1; + break; + case CMDS_PARAM_CRYPTO_TYPE: param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); if (!strncmp("none", buf, 4)) break; if (!strncmp("aes256", buf, 6)) break; knet_vty_write(vty, "unknown encryption method: %s. Supported: none/aes256%s", param, telnet_newline); err = -1; break; - case CMDS_PARAM_HASH: + case CMDS_PARAM_HASH_TYPE: param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); if (!strncmp("none", buf, 4)) break; if (!strncmp("md5", buf, 3)) break; if (!strncmp("sha1", buf, 4)) break; if (!strncmp("sha256", buf, 6)) break; if (!strncmp("sha384", buf, 6)) break; if (!strncmp("sha512", buf, 6)) break; knet_vty_write(vty, "unknown hash method: %s. Supported none/md5/sha1/sha256/sha384/sha512%s", param, telnet_newline); err = -1; break; default: knet_vty_write(vty, "CLI ERROR: unknown parameter type%s", telnet_newline); err = -1; break; } return err; } static void describe_param(struct knet_vty *vty, const int paramtype) { switch(paramtype) { case CMDS_PARAM_NOMORE: knet_vty_write(vty, "no more parameters%s", telnet_newline); break; case CMDS_PARAM_KNET: knet_vty_write(vty, "KNET_IFACE_NAME - interface name (max %d chars) eg: kronosnet0%s", IFNAMSIZ, telnet_newline); break; case CMDS_PARAM_IP: knet_vty_write(vty, "IP address - ipv4 or ipv6 address to add/remove%s", telnet_newline); break; case CMDS_PARAM_IP_PREFIX: knet_vty_write(vty, "IP prefix len (eg. 24, 64)%s", telnet_newline); break; case CMDS_PARAM_IP_PORT: knet_vty_write(vty, "base port (eg: %d) %s", KNET_RING_DEFPORT, telnet_newline); case CMDS_PARAM_BOOL: break; case CMDS_PARAM_INT: break; case CMDS_PARAM_NODEID: knet_vty_write(vty, "NODEID - unique identifier for this interface in this kronos network (value between 0 and 255)%s", telnet_newline); break; case CMDS_PARAM_NAME: knet_vty_write(vty, "NAME - unique name identifier for this entity (max %d chars)%s", KNET_MAX_HOST_LEN - 1, telnet_newline); break; case CMDS_PARAM_MTU: knet_vty_write(vty, "MTU - a value between 576 and 65536 (note: max value depends on the media)%s", telnet_newline); break; - case CMDS_PARAM_CRYPTO: + case CMDS_PARAM_CRYPTO_MODEL: + knet_vty_write(vty, "MODEL - define encryption backend: none or nss%s", telnet_newline); + break; + case CMDS_PARAM_CRYPTO_TYPE: knet_vty_write(vty, "CRYPTO - define packets encryption method: none or aes256%s", telnet_newline); break; - case CMDS_PARAM_HASH: + case CMDS_PARAM_HASH_TYPE: knet_vty_write(vty, "HASH - define packets hashing method: none/md5/sha1/sha256/sha384/sha512%s", telnet_newline); break; default: /* this should never happen */ knet_vty_write(vty, "CLI ERROR: unknown parameter type%s", telnet_newline); break; } } static void print_help(struct knet_vty *vty, const vty_node_cmds_t *cmds, int idx) { if ((idx < 0) || (cmds == NULL) || (cmds[idx].cmd == NULL)) return; if (cmds[idx].help != NULL) { knet_vty_write(vty, "%s\t%s%s", cmds[idx].cmd, cmds[idx].help, telnet_newline); } else { knet_vty_write(vty, "%s\tNo help available for this command%s", cmds[idx].cmd, telnet_newline); } } static int get_param(struct knet_vty *vty, int wanted_paranum, char **param, int *paramlen, int *paramoffset) { int eparams, tparams; const vty_param_t *params = (const vty_param_t *)vty->param; int paramstart = vty->paramoffset; eparams = expected_params(params); tparams = count_words(vty, paramstart); if (tparams > eparams) return -1; if (wanted_paranum == -1) { get_n_word_from_end(vty, 1, param, paramlen, paramoffset); return tparams; } if (tparams < wanted_paranum) return -1; get_n_word_from_end(vty, (tparams - wanted_paranum) + 1, param, paramlen, paramoffset); return tparams - wanted_paranum; } static int match_command(struct knet_vty *vty, const vty_node_cmds_t *cmds, char *cmd, int cmdlen, int cmdoffset, int mode) { int idx = 0, found = -1, paramoffset = 0, paramlen = 0, last_param = 0; char *param = NULL; int paramstart = cmdlen + cmdoffset; int matches[KNET_VTY_MAX_MATCHES]; memset(&matches, -1, sizeof(matches)); while ((cmds[idx].cmd != NULL) && (idx < KNET_VTY_MAX_MATCHES)) { if (!strncmp(cmds[idx].cmd, cmd, cmdlen)) { found++; matches[found] = idx; } idx++; } if (idx >= KNET_VTY_MAX_MATCHES) { knet_vty_write(vty, "Too many matches for this command%s", telnet_newline); return -1; } if (found < 0) { knet_vty_write(vty, "There is no such command%s", telnet_newline); return -1; } switch(mode) { case KNET_VTY_MATCH_HELP: if (found == 0) { if ((cmdoffset <= vty->cursor_pos) && (vty->cursor_pos <= paramstart)) { print_help(vty, cmds, matches[0]); break; } if (cmds[matches[0]].params != NULL) { vty->param = (void *)cmds[matches[0]].params; vty->paramoffset = paramstart; last_param = get_param(vty, -1, ¶m, ¶mlen, ¶moffset); if ((paramoffset <= vty->cursor_pos) && (vty->cursor_pos <= (paramoffset + paramlen))) last_param--; if (last_param >= CMDS_PARAM_NOMORE) { describe_param(vty, cmds[matches[0]].params[last_param].param); if (paramoffset > 0) check_param(vty, cmds[matches[0]].params[last_param].param, param, paramlen); } break; } } if (found >= 0) { idx = 0; while (matches[idx] >= 0) { print_help(vty, cmds, matches[idx]); idx++; } } break; case KNET_VTY_MATCH_EXEC: if (found == 0) { int exec = 0; if (cmds[matches[0]].params != NULL) { int eparams, tparams; eparams = expected_params(cmds[matches[0]].params); tparams = count_words(vty, paramstart); if (eparams != tparams) { exec = -1; idx = 0; knet_vty_write(vty, "Parameter required for this command:%s", telnet_newline); while(cmds[matches[0]].params[idx].param != CMDS_PARAM_NOMORE) { describe_param(vty, cmds[matches[0]].params[idx].param); idx++; } break; } idx = 0; vty->param = (void *)cmds[matches[0]].params; vty->paramoffset = paramstart; while(cmds[matches[0]].params[idx].param != CMDS_PARAM_NOMORE) { get_param(vty, idx + 1, ¶m, ¶mlen, ¶moffset); if (check_param(vty, cmds[matches[0]].params[idx].param, param, paramlen) < 0) { exec = -1; if (vty->filemode) return -1; } idx++; } } if (!exec) { if (cmds[matches[0]].params != NULL) { vty->param = (void *)cmds[matches[0]].params; vty->paramoffset = paramstart; } if (cmds[matches[0]].func != NULL) { return cmds[matches[0]].func(vty); } else { /* this will eventually disappear */ knet_vty_write(vty, "no fn associated to this command%s", telnet_newline); } } } if (found > 0) { knet_vty_write(vty, "Ambiguous command.%s", telnet_newline); } break; case KNET_VTY_MATCH_EXPAND: if (found == 0) { int cmdreallen; if (vty->cursor_pos > cmdoffset+cmdlen) /* complete param? */ break; cmdreallen = strlen(cmds[matches[0]].cmd); memset(vty->line + cmdoffset, 0, cmdlen); memcpy(vty->line + cmdoffset, cmds[matches[0]].cmd, cmdreallen); vty->line[cmdreallen + cmdoffset] = ' '; vty->line_idx = cmdreallen + cmdoffset + 1; vty->cursor_pos = cmdreallen + cmdoffset + 1; } if (found > 0) { /* add completion to string base root */ int count = 0; idx = 0; while (matches[idx] >= 0) { knet_vty_write(vty, "%s\t\t", cmds[matches[idx]].cmd); idx++; count++; if (count == 4) { knet_vty_write(vty, "%s",telnet_newline); count = 0; } } knet_vty_write(vty, "%s",telnet_newline); } break; default: /* this should never really happen */ log_info("Unknown match mode"); break; } return found; } /* forward declarations */ /* common to almost all nodes */ static int knet_cmd_logout(struct knet_vty *vty); static int knet_cmd_who(struct knet_vty *vty); static int knet_cmd_exit_node(struct knet_vty *vty); static int knet_cmd_help(struct knet_vty *vty); /* root node */ static int knet_cmd_config(struct knet_vty *vty); /* config node */ static int knet_cmd_interface(struct knet_vty *vty); static int knet_cmd_no_interface(struct knet_vty *vty); static int knet_cmd_show_conf(struct knet_vty *vty); static int knet_cmd_write_conf(struct knet_vty *vty); /* interface node */ static int knet_cmd_mtu(struct knet_vty *vty); static int knet_cmd_no_mtu(struct knet_vty *vty); static int knet_cmd_ip(struct knet_vty *vty); static int knet_cmd_no_ip(struct knet_vty *vty); static int knet_cmd_baseport(struct knet_vty *vty); static int knet_cmd_peer(struct knet_vty *vty); static int knet_cmd_no_peer(struct knet_vty *vty); static int knet_cmd_start(struct knet_vty *vty); static int knet_cmd_stop(struct knet_vty *vty); +static int knet_cmd_crypto(struct knet_vty *vty); /* peer node */ static int knet_cmd_link(struct knet_vty *vty); static int knet_cmd_no_link(struct knet_vty *vty); /* root node description */ vty_node_cmds_t root_cmds[] = { { "configure", "enter configuration mode", NULL, knet_cmd_config }, { "exit", "exit from CLI", NULL, knet_cmd_logout }, { "help", "display basic help", NULL, knet_cmd_help }, { "logout", "exit from CLI", NULL, knet_cmd_logout }, { "who", "display users connected to CLI", NULL, knet_cmd_who }, { NULL, NULL, NULL, NULL }, }; /* config node description */ vty_param_t no_int_params[] = { { CMDS_PARAM_KNET }, { CMDS_PARAM_NOMORE }, }; vty_node_cmds_t no_config_cmds[] = { { "interface", "destroy kronosnet interface", no_int_params, knet_cmd_no_interface }, { NULL, NULL, NULL, NULL }, }; vty_param_t int_params[] = { { CMDS_PARAM_KNET }, { CMDS_PARAM_NODEID }, - { CMDS_PARAM_CRYPTO }, - { CMDS_PARAM_HASH }, { CMDS_PARAM_NOMORE }, }; vty_node_cmds_t config_cmds[] = { { "exit", "exit configuration mode", NULL, knet_cmd_exit_node }, { "interface", "configure kronosnet interface", int_params, knet_cmd_interface }, { "show", "show running config", NULL, knet_cmd_show_conf }, { "help", "display basic help", NULL, knet_cmd_help }, { "logout", "exit from CLI", NULL, knet_cmd_logout }, { "no", "revert command", NULL, NULL }, { "who", "display users connected to CLI", NULL, knet_cmd_who }, { "write", "write current config to file", NULL, knet_cmd_write_conf }, { NULL, NULL, NULL, NULL }, }; /* interface node description */ vty_param_t ip_params[] = { { CMDS_PARAM_IP }, { CMDS_PARAM_IP_PREFIX }, { CMDS_PARAM_NOMORE }, }; vty_param_t peer_params[] = { { CMDS_PARAM_NAME }, { CMDS_PARAM_NODEID }, { CMDS_PARAM_NOMORE }, }; vty_node_cmds_t no_interface_cmds[] = { { "ip", "remove ip address", ip_params, knet_cmd_no_ip }, { "mtu", "revert to default MTU", NULL, knet_cmd_no_mtu }, { "peer", "remove peer from this interface", peer_params, knet_cmd_no_peer }, { NULL, NULL, NULL, NULL }, }; vty_param_t mtu_params[] = { { CMDS_PARAM_MTU }, { CMDS_PARAM_NOMORE }, }; vty_param_t baseport_params[] = { { CMDS_PARAM_IP_PORT }, { CMDS_PARAM_NOMORE }, }; +vty_param_t crypto_params[] = { + { CMDS_PARAM_CRYPTO_MODEL }, + { CMDS_PARAM_CRYPTO_TYPE }, + { CMDS_PARAM_HASH_TYPE }, + { CMDS_PARAM_NOMORE }, +}; + vty_node_cmds_t interface_cmds[] = { { "baseport", "set base listening port for this interface", baseport_params, knet_cmd_baseport }, + { "crypto", "enable crypto/hmac", crypto_params, knet_cmd_crypto }, { "exit", "exit configuration mode", NULL, knet_cmd_exit_node }, { "help", "display basic help", NULL, knet_cmd_help }, { "ip", "add ip address", ip_params, knet_cmd_ip }, { "logout", "exit from CLI", NULL, knet_cmd_logout }, { "mtu", "set mtu", mtu_params, knet_cmd_mtu }, { "no", "revert command", NULL, NULL }, { "peer", "add peer endpoint", peer_params, knet_cmd_peer }, { "show", "show running config", NULL, knet_cmd_show_conf }, { "start", "start forwarding engine", NULL, knet_cmd_start }, { "stop", "stop forwarding engine", NULL, knet_cmd_stop }, { "who", "display users connected to CLI", NULL, knet_cmd_who }, { "write", "write current config to file", NULL, knet_cmd_write_conf }, { NULL, NULL, NULL, NULL }, }; /* peer node description */ vty_param_t link_params[] = { { CMDS_PARAM_IP }, { CMDS_PARAM_NOMORE }, }; vty_node_cmds_t no_peer_cmds[] = { { "link", "remove peer endpoint", link_params, knet_cmd_no_link}, { NULL, NULL, NULL, NULL }, }; vty_node_cmds_t peer_cmds[] = { { "exit", "exit configuration mode", NULL, knet_cmd_exit_node }, { "help", "display basic help", NULL, knet_cmd_help }, { "link", "add peer endpoint", link_params, knet_cmd_link }, { "logout", "exit from CLI", NULL, knet_cmd_logout }, { "no", "revert command", NULL, NULL }, { "show", "show running config", NULL, knet_cmd_show_conf }, { "who", "display users connected to CLI", NULL, knet_cmd_who }, { "write", "write current config to file", NULL, knet_cmd_write_conf }, { NULL, NULL, NULL, NULL }, }; /* link node description */ vty_node_cmds_t link_cmds[] = { { "exit", "exit configuration mode", NULL, knet_cmd_exit_node }, { "help", "display basic help", NULL, knet_cmd_help }, { "logout", "exit from CLI", NULL, knet_cmd_logout }, { "no", "revert command", NULL, NULL }, { "show", "show running config", NULL, knet_cmd_show_conf }, { "who", "display users connected to CLI", NULL, knet_cmd_who }, { "write", "write current config to file", NULL, knet_cmd_write_conf }, { NULL, NULL, NULL, NULL }, }; /* nodes */ vty_nodes_t knet_vty_nodes[] = { { NODE_ROOT, "knet", root_cmds, NULL }, { NODE_CONFIG, "config", config_cmds, no_config_cmds }, { NODE_INTERFACE, "iface", interface_cmds, no_interface_cmds }, { NODE_PEER, "peer", peer_cmds, no_peer_cmds }, { NODE_LINK, "link", link_cmds, NULL }, { -1, NULL, NULL }, }; /* command execution */ /* links */ static int knet_cmd_no_link(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; struct knet_host *host = (struct knet_host *)vty->host; int j, paramlen = 0, paramoffset = 0, found = 0; char *param = NULL; char ipaddr[KNET_MAX_HOST_LEN], port[6]; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(ipaddr, KNET_MAX_HOST_LEN, param, paramlen); memset(port, 0, sizeof(port)); snprintf(port, 6, "%d", knet_iface->cfg_ring.base_port + knet_iface->cfg_eth.node_id); for (j = 0; j < KNET_MAX_LINK; j++) { if (!strcmp(host->link[j].ipaddr, ipaddr) && !strcmp(host->link[j].port, port)) { found = 1; break; } } if (!found) { knet_vty_write(vty, "Error: unable to find link%s", telnet_newline); return -1; } host->link[j].configured = 0; if (knet_host_dst_cache_update(knet_iface->cfg_ring.knet_h, host->node_id)) knet_vty_write(vty, "Error: unable to update switching cache%s", telnet_newline); return 0; } static int knet_cmd_link(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; struct knet_host *host = (struct knet_host *)vty->host; struct knet_link *klink = NULL; int j, paramlen = 0, paramoffset = 0, err = 0, found = 0; char *param = NULL; char ipaddr[KNET_MAX_HOST_LEN], port[6]; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(ipaddr, KNET_MAX_HOST_LEN, param, paramlen); memset(port, 0, sizeof(port)); snprintf(port, 6, "%d", knet_iface->cfg_ring.base_port + knet_iface->cfg_eth.node_id); for (j = 0; j < KNET_MAX_LINK; j++) { if ((klink == NULL) && (host->link[j].configured == 0)) { klink = &host->link[j]; } if (!strcmp(host->link[j].ipaddr, ipaddr) && !strcmp(host->link[j].port, port)) { found = 1; break; } } if (!found) { if (!klink) { knet_vty_write(vty, "Error: all links are in use!%s", telnet_newline); return -1; } memcpy(klink->ipaddr, ipaddr, strlen(ipaddr)); memcpy(klink->port, port, strlen(port)); if (strtoaddr(klink->ipaddr, klink->port, (struct sockaddr *)&klink->address, sizeof(klink->address)) != 0) { knet_vty_write(vty, "Error: unable to convert ip addr to sockaddr!%s", telnet_newline); err = -1; goto out_clean; } klink->sock = host->listener->sock; knet_link_timeout(klink, 1000, 5000, 2048); klink->configured = 1; } vty->link = (void *)klink; vty->node = NODE_LINK; out_clean: return err; } static int knet_find_host(struct knet_vty *vty, struct knet_host **host, const char *nodename, const uint16_t requested_node_id) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; struct knet_host *head = NULL; int err = 0; *host = NULL; if (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head)) { knet_vty_write(vty, "Error: unable to acquire lock on peer list!%s", telnet_newline); return -1; } while (head != NULL) { if (!strcmp(head->name, nodename)) { if (head->node_id == requested_node_id) { *host = head; err = 1; goto out_clean; } else { knet_vty_write(vty, "Error: requested peer exists with another nodeid%s", telnet_newline); err = -1; goto out_clean; } } else { if (head->node_id == requested_node_id) { knet_vty_write(vty, "Error: requested peer nodeid already exists%s", telnet_newline); err = -1; goto out_clean; } } head = head->next; } out_clean: while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) { knet_vty_write(vty, "Error: unable to release lock on peer list!%s", telnet_newline); sleep(1); } return err; } static int knet_cmd_no_peer(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int paramlen = 0, paramoffset = 0, requested_node_id = 0, err = 0; char *param = NULL; struct knet_host *host = NULL; char nodename[KNET_MAX_HOST_LEN]; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(nodename, sizeof(nodename), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); requested_node_id = param_to_int(param, paramlen); if (requested_node_id == knet_iface->cfg_eth.node_id) { knet_vty_write(vty, "Error: remote peer id cannot be the same as local id%s", telnet_newline); return -1; } err = knet_find_host(vty, &host, nodename, requested_node_id); if (err < 0) goto out_clean; if (err == 0) { knet_vty_write(vty, "Error: peer not found in list%s", telnet_newline); goto out_clean; } if (host->listener) { if (knet_listener_remove(knet_iface->cfg_ring.knet_h, host->listener) == -EBUSY) { knet_vty_write(vty, "Error: unable to remove listener from current peer%s", telnet_newline); err = -1; goto out_clean; } } if (knet_host_remove(knet_iface->cfg_ring.knet_h, requested_node_id) < 0) { knet_vty_write(vty, "Error: unable to remove peer from current config%s", telnet_newline); err = -1; goto out_clean; } out_clean: return err; } static int knet_cmd_peer(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int paramlen = 0, paramoffset = 0, requested_node_id = 0, err = 0; char *param = NULL; struct knet_host *host, *temp = NULL; struct knet_listener *listener = NULL; char nodename[KNET_MAX_HOST_LEN]; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(nodename, sizeof(nodename), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); requested_node_id = param_to_int(param, paramlen); if (requested_node_id == knet_iface->cfg_eth.node_id) { knet_vty_write(vty, "Error: remote peer id cannot be the same as local id%s", telnet_newline); return -1; } err = knet_find_host(vty, &host, nodename, requested_node_id); if (err < 0) goto out_clean; if (err == 0) { if (knet_host_add(knet_iface->cfg_ring.knet_h, requested_node_id) < 0) { knet_vty_write(vty, "Error: unable to allocate memory for host struct!%s", telnet_newline); err = -1; goto out_clean; } knet_host_get(knet_iface->cfg_ring.knet_h, requested_node_id, &temp); host = temp; knet_host_release(knet_iface->cfg_ring.knet_h, &temp); memcpy(host->name, nodename, strlen(nodename)); host->link_handler_policy = KNET_LINK_POLICY_PASSIVE; listener = malloc(sizeof(struct knet_listener)); if (!listener) { knet_vty_write(vty, "Error: unable to allocate memory for listener struct!%s", telnet_newline); err = -1; goto out_clean; } memset(listener, 0, sizeof(struct knet_listener)); snprintf(listener->ipaddr, KNET_MAX_HOST_LEN, "::"); snprintf(listener->port, 6, "%d", knet_iface->cfg_ring.base_port + requested_node_id); if (strtoaddr(listener->ipaddr, listener->port, (struct sockaddr *)&listener->address, sizeof(listener->address)) != 0) { knet_vty_write(vty, "Error: unable to convert ip addr to sockaddr!%s", telnet_newline); err = -1; goto out_clean; } if (knet_listener_add(knet_iface->cfg_ring.knet_h, listener) != 0) { knet_vty_write(vty, "Error: unable to start listener!%s", telnet_newline); err = -1; goto out_clean; } host->listener = listener; } vty->host = (void *)host; vty->node = NODE_PEER; out_clean: if (err < 0) { if (listener) free(listener); if (host) knet_host_remove(knet_iface->cfg_ring.knet_h, host->node_id); } return err; } static int active_listeners(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; struct knet_host *head = NULL; int listeners = 0; if (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head)) { knet_vty_write(vty, "Error: unable to acquire lock on peer list!%s", telnet_newline); return -1; } while (head != NULL) { if (head->listener) listeners++; head = head->next; } while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) { knet_vty_write(vty, "Error: unable to release lock on peer list!%s", telnet_newline); sleep(1); } return listeners; } static int knet_cmd_baseport(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int paramlen = 0, paramoffset = 0, err = 0; char *param = NULL; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); /* need to check if baseport is in use by other interfaces */ err = active_listeners(vty); if (!err) { knet_iface->cfg_ring.base_port = param_to_int(param, paramlen); } if (err > 0) { knet_vty_write(vty, "Error: cannot switch baseport when listeners are active%s", telnet_newline); err = -1; } return err; } static int knet_cmd_no_ip(struct knet_vty *vty) { int paramlen = 0, paramoffset = 0; char *param = NULL; char ipaddr[KNET_MAX_HOST_LEN], prefix[4]; struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; char *error_string = NULL; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(ipaddr, sizeof(ipaddr), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); param_to_str(prefix, sizeof(prefix), param, paramlen); if (tap_del_ip(knet_iface->cfg_eth.tap, ipaddr, prefix, &error_string) < 0) { knet_vty_write(vty, "Error: Unable to del ip addr %s/%s on device %s%s", ipaddr, prefix, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); if (error_string) { knet_vty_write(vty, "(%s)%s", error_string, telnet_newline); free(error_string); } return -1; } return 0; } static int knet_cmd_ip(struct knet_vty *vty) { int paramlen = 0, paramoffset = 0; char *param = NULL; char ipaddr[512], prefix[4]; struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; char *error_string = NULL; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(ipaddr, sizeof(ipaddr), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); param_to_str(prefix, sizeof(prefix), param, paramlen); if (tap_add_ip(knet_iface->cfg_eth.tap, ipaddr, prefix, &error_string) < 0) { knet_vty_write(vty, "Error: Unable to set ip addr %s/%s on device %s%s", ipaddr, prefix, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); if (error_string) { knet_vty_write(vty, "(%s)%s", error_string, telnet_newline); free(error_string); } return -1; } return 0; } static int knet_cmd_no_mtu(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; if (tap_reset_mtu(knet_iface->cfg_eth.tap) < 0) { knet_vty_write(vty, "Error: Unable to set default mtu on device %s%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); return -1; } return 0; } static int knet_cmd_mtu(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int paramlen = 0, paramoffset = 0, expected_mtu = 0; char *param = NULL; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); expected_mtu = param_to_int(param, paramlen); if (tap_set_mtu(knet_iface->cfg_eth.tap, expected_mtu) < 0) { knet_vty_write(vty, "Error: Unable to set requested mtu %d on device %s%s", expected_mtu, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); return -1; } return 0; } static int knet_cmd_stop(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; char *error_down = NULL, *error_postdown = NULL; int err = 0; err = tap_set_down(knet_iface->cfg_eth.tap, &error_down, &error_postdown); if (err < 0) { knet_vty_write(vty, "Error: Unable to set interface %s down!%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); } else { knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 0); knet_iface->active = 0; } if (error_down) { knet_vty_write(vty, "down script output:%s(%s)%s", telnet_newline, error_down, telnet_newline); free(error_down); } if (error_postdown) { knet_vty_write(vty, "post-down script output:%s(%s)%s", telnet_newline, error_postdown, telnet_newline); free(error_postdown); } return err; } +static int knet_cmd_crypto(struct knet_vty *vty) +{ + struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; + int paramlen = 0, paramoffset = 0; + char *param = NULL; + int err = 0; + + if (knet_iface->active) { + knet_vty_write(vty, "Error: Unable to activate encryption while interface is active%s", telnet_newline); + return -1; + } + + get_param(vty, 1, ¶m, ¶mlen, ¶moffset); + param_to_str(knet_iface->knet_handle_crypto_cfg.crypto_model, + sizeof(knet_iface->knet_handle_crypto_cfg.crypto_model), param, paramlen); + + get_param(vty, 2, ¶m, ¶mlen, ¶moffset); + param_to_str(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type, + sizeof(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type), param, paramlen); + + get_param(vty, 3, ¶m, ¶mlen, ¶moffset); + param_to_str(knet_iface->knet_handle_crypto_cfg.crypto_hash_type, + sizeof(knet_iface->knet_handle_crypto_cfg.crypto_hash_type), param, paramlen); + + if ((strncmp("none", knet_iface->knet_handle_crypto_cfg.crypto_cipher_type, 4)) || + (strncmp("none", knet_iface->knet_handle_crypto_cfg.crypto_hash_type, 4))) { + int fd = -1; + char keyfile[PATH_MAX]; + struct stat sb; + + memset(keyfile, 0, PATH_MAX); + snprintf(keyfile, PATH_MAX - 1, DEFAULT_CONFIG_DIR "/cryptokeys.d/%s", tap_get_name(knet_iface->cfg_eth.tap)); + + fd = open(keyfile, O_RDONLY); + if (fd < 0) { + knet_vty_write(vty, "Error: Unable to open security key: %s%s", keyfile, telnet_newline); + err = -1; + return -1; + } + + if (fstat(fd, &sb)) { + knet_vty_write(vty, "Error: Unable to verify security key: %s%s", keyfile, telnet_newline); + goto key_error; + } + + if (!S_ISREG(sb.st_mode)) { + knet_vty_write(vty, "Error: Key %s does not appear to be a regular file%s", + keyfile, telnet_newline); + goto key_error; + } + + knet_iface->knet_handle_crypto_cfg.private_key_len = (unsigned int)sb.st_size; + if ((knet_iface->knet_handle_crypto_cfg.private_key_len < KNET_MIN_KEY_LEN) || + (knet_iface->knet_handle_crypto_cfg.private_key_len > KNET_MAX_KEY_LEN)) { + knet_vty_write(vty, "Error: Key %s is %u long. Must be %u <= key_len <= %u%s", + keyfile, knet_iface->knet_handle_crypto_cfg.private_key_len, + KNET_MIN_KEY_LEN, KNET_MAX_KEY_LEN, telnet_newline); + goto key_error; + } + + if (((sb.st_mode & S_IRWXU) != S_IRUSR) || + (sb.st_mode & S_IRWXG) || + (sb.st_mode & S_IRWXO)) { + knet_vty_write(vty, "Error: Key %s does not have the correct permission (must be user read-only)%s", + keyfile, telnet_newline); + goto key_error; + } + if (read(fd, + &knet_iface->knet_handle_crypto_cfg.private_key, + knet_iface->knet_handle_crypto_cfg.private_key_len) != knet_iface->knet_handle_crypto_cfg.private_key_len) { + knet_vty_write(vty, "Error: Unable to read key %s%s", keyfile, telnet_newline); + goto key_error; + } + + close(fd); + goto key_clean; + +key_error: + close(fd); + err = -1; + } +key_clean: + + if (!err) { + err = knet_handle_crypto(knet_iface->cfg_ring.knet_h, + &knet_iface->knet_handle_crypto_cfg); + } + + return err; +} + static int knet_cmd_start(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; char *error_preup = NULL, *error_up = NULL; int err = 0; err = tap_set_up(knet_iface->cfg_eth.tap, &error_preup, &error_up); if (err < 0) { knet_vty_write(vty, "Error: Unable to set interface %s up!%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 0); } else { knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 1); knet_iface->active = 1; } if (error_preup) { knet_vty_write(vty, "pre-up script output:%s(%s)%s", telnet_newline, error_preup, telnet_newline); free(error_preup); } if (error_up) { knet_vty_write(vty, "up script output:%s(%s)%s", telnet_newline, error_up, telnet_newline); free(error_up); } return err; } static int knet_cmd_no_interface(struct knet_vty *vty) { int err = 0, paramlen = 0, paramoffset = 0; char *param = NULL; char device[IFNAMSIZ]; struct knet_cfg *knet_iface = NULL; struct knet_host *host; char *ip_list = NULL; int ip_list_entries = 0, i, offset = 0; char *error_string = NULL; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(device, IFNAMSIZ, param, paramlen); knet_iface = knet_get_iface(device, 0); if (!knet_iface) { knet_vty_write(vty, "Error: Unable to find requested interface%s", telnet_newline); return -1; } vty->iface = (void *)knet_iface; tap_get_ips(knet_iface->cfg_eth.tap, &ip_list, &ip_list_entries); if ((ip_list) && (ip_list_entries > 0)) { for (i = 1; i <= ip_list_entries; i++) { tap_del_ip(knet_iface->cfg_eth.tap, ip_list + offset, ip_list + offset + strlen(ip_list + offset) + 1, &error_string); if (error_string) { free(error_string); error_string = NULL; } offset = offset + strlen(ip_list) + 1; offset = offset + strlen(ip_list + offset) + 1; } free(ip_list); ip_list = NULL; ip_list_entries = 0; } while (1) { struct knet_host *head; while (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head) != 0) { log_error("CLI ERROR: unable to acquire peer lock.. will retry in 1 sec"); sleep (1); } if (head == NULL) break; host = head; while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) { log_error("CLI ERROR: unable to release peer lock.. will retry in 1 sec"); sleep (1); } for (i = 0; i < KNET_MAX_LINK; i++) host->link[i].configured = 0; knet_listener_remove(knet_iface->cfg_ring.knet_h, host->listener); while (knet_host_remove(knet_iface->cfg_ring.knet_h, host->node_id) != 0) { log_error("CLI ERROR: unable to release peer.. will retry in 1 sec"); sleep (1); } } knet_cmd_stop(vty); if (knet_iface->cfg_ring.knet_h) knet_handle_free(knet_iface->cfg_ring.knet_h); if (knet_iface->cfg_eth.tap) tap_close(knet_iface->cfg_eth.tap); if (knet_iface) knet_destroy_iface(knet_iface); return err; } static int knet_cmd_interface(struct knet_vty *vty) { int err = 0, paramlen = 0, paramoffset = 0, found = 0, requested_id; char *param = NULL; char device[IFNAMSIZ]; - char crypto[16]; - char hash[16]; char mac[18]; struct knet_cfg *knet_iface = NULL; struct knet_handle_cfg knet_handle_cfg; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(device, IFNAMSIZ, param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); requested_id = param_to_int(param, paramlen); knet_iface = knet_get_iface(device, 1); if (!knet_iface) { knet_vty_write(vty, "Error: Unable to allocate memory for config structures%s", telnet_newline); return -1; } - get_param(vty, 3, ¶m, ¶mlen, ¶moffset); - param_to_str(crypto, sizeof(crypto), param, paramlen); - knet_iface->crypto_method = strdup(crypto); - if (!knet_iface->crypto_method) { - err = -1; - goto out_clean; - } - - get_param(vty, 4, ¶m, ¶mlen, ¶moffset); - param_to_str(hash, sizeof(hash), param, paramlen); - knet_iface->hash_method = strdup(hash); - if (!knet_iface->hash_method) { - err = -1; - goto out_clean; - } - if (knet_iface->cfg_eth.tap) { found = 1; goto tap_found; } if (!knet_iface->cfg_eth.tap) knet_iface->cfg_eth.tap = tap_open(device, IFNAMSIZ, DEFAULT_CONFIG_DIR); if ((!knet_iface->cfg_eth.tap) && (errno = EBUSY)) { knet_vty_write(vty, "Error: interface %s seems to exist in the system%s", device, telnet_newline); err = -1; goto out_clean; } if (!knet_iface->cfg_eth.tap) { knet_vty_write(vty, "Error: Unable to create %s system tap device%s", device, telnet_newline); err = -1; goto out_clean; } tap_found: if (knet_iface->cfg_ring.knet_h) goto knet_found; memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg)); knet_handle_cfg.fd = tap_get_fd(knet_iface->cfg_eth.tap); knet_handle_cfg.node_id = requested_id; - knet_handle_cfg.crypto_cipher_type = knet_iface->crypto_method; - knet_handle_cfg.crypto_hash_type = knet_iface->hash_method; knet_handle_cfg.dst_host_filter = KNET_DST_FILTER_ENABLE; knet_handle_cfg.dst_host_filter_fn = ether_host_filter_fn; - if ((strncmp("none", knet_iface->crypto_method, 4)) || - (strncmp("none", knet_iface->hash_method, 4))) { - int fd = -1; - char keyfile[PATH_MAX]; - unsigned char private_key[KNET_MAX_KEY_LEN]; - struct stat sb; - - memset(keyfile, 0, PATH_MAX); - snprintf(keyfile, PATH_MAX - 1, DEFAULT_CONFIG_DIR "/cryptokeys.d/%s", device); - - fd = open(keyfile, O_RDONLY); - if (fd < 0) { - knet_vty_write(vty, "Error: Unable to open security key: %s%s", keyfile, telnet_newline); - err = -1; - goto out_clean; - } - - if (fstat(fd, &sb)) { - knet_vty_write(vty, "Error: Unable to verify security key: %s%s", keyfile, telnet_newline); - goto key_error; - } - - if (!S_ISREG(sb.st_mode)) { - knet_vty_write(vty, "Error: Key %s does not appear to be a regular file%s", - keyfile, telnet_newline); - goto key_error; - } - - knet_handle_cfg.private_key_len = (unsigned int)sb.st_size; - if ((knet_handle_cfg.private_key_len < KNET_MIN_KEY_LEN) || - (knet_handle_cfg.private_key_len > KNET_MAX_KEY_LEN)) { - knet_vty_write(vty, "Error: Key %s is %u long. Must be %u <= key_len <= %u%s", - keyfile, knet_handle_cfg.private_key_len, - KNET_MIN_KEY_LEN, KNET_MAX_KEY_LEN, telnet_newline); - goto key_error; - } - - if (((sb.st_mode & S_IRWXU) != S_IRUSR) || - (sb.st_mode & S_IRWXG) || - (sb.st_mode & S_IRWXO)) { - knet_vty_write(vty, "Error: Key %s does not have the correct permission (must be user read-only)%s", - keyfile, telnet_newline); - goto key_error; - } - - memset(&private_key, 0, sizeof(private_key)); - - if (read(fd, &private_key, knet_handle_cfg.private_key_len) != knet_handle_cfg.private_key_len) { - knet_vty_write(vty, "Error: Unable to read key %s%s", keyfile, telnet_newline); - goto key_error; - } - - knet_handle_cfg.private_key = private_key; - - close(fd); - goto key_clean; - -key_error: - close(fd); - err = -1; - goto out_clean; - } - -key_clean: knet_iface->cfg_ring.knet_h = knet_handle_new(&knet_handle_cfg); if (!knet_iface->cfg_ring.knet_h) { knet_vty_write(vty, "Error: Unable to create ring handle for device %s%s", device, telnet_newline); err = -1; goto out_clean; } knet_found: if (found) { if (requested_id == knet_iface->cfg_eth.node_id) goto out_found; knet_vty_write(vty, "Error: no interface %s with nodeid %d found%s", device, requested_id, telnet_newline); goto out_clean; } else { knet_iface->cfg_eth.node_id = requested_id; } memset(&mac, 0, sizeof(mac)); snprintf(mac, sizeof(mac) - 1, "54:54:0:0:0:%x", knet_iface->cfg_eth.node_id); if (tap_set_mac(knet_iface->cfg_eth.tap, mac) < 0) { knet_vty_write(vty, "Error: Unable to set mac address %s on device %s%s", mac, device, telnet_newline); err = -1; goto out_clean; } out_found: vty->node = NODE_INTERFACE; vty->iface = (void *)knet_iface; out_clean: if (err) { if (knet_iface->cfg_ring.knet_h) knet_handle_free(knet_iface->cfg_ring.knet_h); if (knet_iface->cfg_eth.tap) tap_close(knet_iface->cfg_eth.tap); knet_destroy_iface(knet_iface); } return err; } static int knet_cmd_exit_node(struct knet_vty *vty) { knet_vty_exit_node(vty); return 0; } static int knet_cmd_print_conf(struct knet_vty *vty) { int i; struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg; struct knet_host *host = NULL; const char *nl = telnet_newline; char *ip_list = NULL; int ip_list_entries = 0, offset = 0; if (vty->filemode) nl = file_newline; knet_vty_write(vty, "configure%s", nl); while (knet_iface != NULL) { - knet_vty_write(vty, " interface %s %u %s %s%s", tap_get_name(knet_iface->cfg_eth.tap), - knet_iface->cfg_eth.node_id, - knet_iface->crypto_method, - knet_iface->hash_method, nl); + knet_vty_write(vty, " interface %s %u%s", tap_get_name(knet_iface->cfg_eth.tap), + knet_iface->cfg_eth.node_id, nl); knet_vty_write(vty, " mtu %d%s", tap_get_mtu(knet_iface->cfg_eth.tap), nl); tap_get_ips(knet_iface->cfg_eth.tap, &ip_list, &ip_list_entries); if ((ip_list) && (ip_list_entries > 0)) { for (i = 1; i <= ip_list_entries; i++) { knet_vty_write(vty, " ip %s %s%s", ip_list + offset, ip_list + offset + strlen(ip_list + offset) + 1, nl); offset = offset + strlen(ip_list) + 1; offset = offset + strlen(ip_list + offset) + 1; } free(ip_list); ip_list = NULL; ip_list_entries = 0; } knet_vty_write(vty, " baseport %d%s", knet_iface->cfg_ring.base_port, nl); + knet_vty_write(vty, " crypto %s %s %s%s", + knet_iface->knet_handle_crypto_cfg.crypto_model, + knet_iface->knet_handle_crypto_cfg.crypto_cipher_type, + knet_iface->knet_handle_crypto_cfg.crypto_hash_type, nl); + while (knet_host_acquire(knet_iface->cfg_ring.knet_h, &host)) { log_error("CLI ERROR: waiting for peer lock"); sleep(1); } while (host != NULL) { knet_vty_write(vty, " peer %s %u%s", host->name, host->node_id, nl); for (i = 0; i < KNET_MAX_LINK; i++) { if (host->link[i].configured == 1) { knet_vty_write(vty, " link %s%s", host->link[i].ipaddr, nl); /* print link properties */ knet_vty_write(vty, " exit%s", nl); } } knet_vty_write(vty, " exit%s", nl); host = host->next; } while (knet_host_release(knet_iface->cfg_ring.knet_h, &host) != 0) { log_error("CLI ERROR: unable to release peer lock.. will retry in 1 sec"); sleep(1); } if (knet_iface->active) knet_vty_write(vty, " start%s", nl); knet_vty_write(vty, " exit%s", nl); knet_iface = knet_iface->next; } knet_vty_write(vty, " exit%sexit%s", nl, nl); return 0; } static int knet_cmd_show_conf(struct knet_vty *vty) { return knet_cmd_print_conf(vty); } static int knet_cmd_write_conf(struct knet_vty *vty) { int fd = 1, vty_sock, err = 0, backup = 1; char tempfile[PATH_MAX]; memset(tempfile, 0, sizeof(tempfile)); snprintf(tempfile, sizeof(tempfile), "%s.sav", knet_cfg_head.conffile); err = rename(knet_cfg_head.conffile, tempfile); if ((err < 0) && (errno != ENOENT)) { knet_vty_write(vty, "Unable to create backup config file %s %s", tempfile, telnet_newline); return -1; } if ((err < 0) && (errno == ENOENT)) backup = 0; fd = open(knet_cfg_head.conffile, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) { knet_vty_write(vty, "Error unable to open file%s", telnet_newline); return -1; } vty_sock = vty->vty_sock; vty->vty_sock = fd; vty->filemode = 1; knet_cmd_print_conf(vty); vty->vty_sock = vty_sock; vty->filemode = 0; close(fd); knet_vty_write(vty, "Configuration saved to %s%s", knet_cfg_head.conffile, telnet_newline); if (backup) knet_vty_write(vty, "Old configuration file has been stored in %s%s", tempfile, telnet_newline); return err; } static int knet_cmd_config(struct knet_vty *vty) { int err = 0; if (!vty->user_can_enable) { knet_vty_write(vty, "Error: user %s does not have enough privileges to perform config operations%s", vty->username, telnet_newline); return -1; } pthread_mutex_lock(&knet_vty_mutex); if (knet_vty_config >= 0) { knet_vty_write(vty, "Error: configuration is currently locked by user %s on vty(%d). Try again later%s", vty->username, knet_vty_config, telnet_newline); err = -1; goto out_clean; } vty->node = NODE_CONFIG; knet_vty_config = vty->conn_num; out_clean: pthread_mutex_unlock(&knet_vty_mutex); return err; } static int knet_cmd_logout(struct knet_vty *vty) { vty->got_epipe = 1; return 0; } static int knet_cmd_who(struct knet_vty *vty) { int conn_index; pthread_mutex_lock(&knet_vty_mutex); for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) { if (knet_vtys[conn_index].active) { knet_vty_write(vty, "User %s connected on vty(%d) from %s%s", knet_vtys[conn_index].username, knet_vtys[conn_index].conn_num, knet_vtys[conn_index].ip, telnet_newline); } } pthread_mutex_unlock(&knet_vty_mutex); return 0; } static int knet_cmd_help(struct knet_vty *vty) { knet_vty_write(vty, PACKAGE " VTY provides advanced help feature.%s%s" "When you need help, anytime at the command line please press '?'.%s%s" "If nothing matches, the help list will be empty and you must backup%s" " until entering a '?' shows the available options.%s", telnet_newline, telnet_newline, telnet_newline, telnet_newline, telnet_newline, telnet_newline); return 0; } /* exported API to vty_cli.c */ int knet_vty_execute_cmd(struct knet_vty *vty) { const vty_node_cmds_t *cmds = NULL; char *cmd = NULL; int cmdlen = 0; int cmdoffset = 0; if (knet_vty_is_line_empty(vty)) return 0; cmds = get_cmds(vty, &cmd, &cmdlen, &cmdoffset); /* this will eventually disappear. keep it as safeguard for now */ if (cmds == NULL) { knet_vty_write(vty, "No commands associated to this node%s", telnet_newline); return 0; } return match_command(vty, cmds, cmd, cmdlen, cmdoffset, KNET_VTY_MATCH_EXEC); } int knet_read_conf(void) { int err = 0, len = 0, line = 0; struct knet_vty *vty = &knet_vtys[0]; FILE *file = NULL; file = fopen(knet_cfg_head.conffile, "r"); if ((file == NULL) && (errno != ENOENT)) { log_error("Unable to open config file for reading %s", knet_cfg_head.conffile); return -1; } if ((file == NULL) && (errno == ENOENT)) { log_info("Configuration file %s not found, starting with default empty config", knet_cfg_head.conffile); return 0; } vty->vty_sock = 1; vty->user_can_enable = 1; vty->filemode = 1; while(fgets(vty->line, sizeof(vty->line), file) != NULL) { line++; len = strlen(vty->line) - 1; memset(&vty->line[len], 0, 1); vty->line_idx = len; err = knet_vty_execute_cmd(vty); if (err != 0) { log_error("line[%d]: %s", line, vty->line); break; } } fclose(file); memset(vty, 0, sizeof(vty)); return err; } void knet_vty_help(struct knet_vty *vty) { int idx = 0; const vty_node_cmds_t *cmds = NULL; char *cmd = NULL; int cmdlen = 0; int cmdoffset = 0; cmds = get_cmds(vty, &cmd, &cmdlen, &cmdoffset); /* this will eventually disappear. keep it as safeguard for now */ if (cmds == NULL) { knet_vty_write(vty, "No commands associated to this node%s", telnet_newline); return; } if (knet_vty_is_line_empty(vty) || cmd == NULL) { while (cmds[idx].cmd != NULL) { print_help(vty, cmds, idx); idx++; } return; } match_command(vty, cmds, cmd, cmdlen, cmdoffset, KNET_VTY_MATCH_HELP); } void knet_vty_tab_completion(struct knet_vty *vty) { const vty_node_cmds_t *cmds = NULL; char *cmd = NULL; int cmdlen = 0; int cmdoffset = 0; if (knet_vty_is_line_empty(vty)) return; knet_vty_write(vty, "%s", telnet_newline); cmds = get_cmds(vty, &cmd, &cmdlen, &cmdoffset); /* this will eventually disappear. keep it as safeguard for now */ if (cmds == NULL) { knet_vty_write(vty, "No commands associated to this node%s", telnet_newline); return; } match_command(vty, cmds, cmd, cmdlen, cmdoffset, KNET_VTY_MATCH_EXPAND); knet_vty_prompt(vty); knet_vty_write(vty, "%s", vty->line); } diff --git a/libknet/handle.c b/libknet/handle.c index 34d1424d..1edcdf4e 100644 --- a/libknet/handle.c +++ b/libknet/handle.c @@ -1,683 +1,705 @@ #include "config.h" #include #include #include #include #include #include #include "libknet-private.h" #include "nsscrypto.h" #define KNET_MAX_EVENTS 8 #define KNET_PING_TIMERES 200000 static void *_handle_tap_to_links_thread(void *data); static void *_handle_recv_from_links_thread(void *data); static void *_handle_heartbt_thread(void *data); static void *_handle_dst_link_handler_thread(void *data); knet_handle_t knet_handle_new(const struct knet_handle_cfg *knet_handle_cfg) { knet_handle_t knet_h; struct epoll_event ev; /* * validate incoming config request */ if (knet_handle_cfg == NULL) { errno = EINVAL; return NULL; } if (knet_handle_cfg->fd <= 0) { errno = EINVAL; return NULL; } if ((knet_h = malloc(sizeof(struct knet_handle))) == NULL) return NULL; memset(knet_h, 0, sizeof(struct knet_handle)); knet_h->node_id = knet_handle_cfg->node_id; knet_h->sockfd = knet_handle_cfg->fd; if (pipe(knet_h->pipefd)) goto exit_fail1; if ((_fdset_cloexec(knet_h->pipefd[0])) || (_fdset_cloexec(knet_h->pipefd[1])) || (_fdset_nonblock(knet_h->pipefd[0])) || (_fdset_nonblock(knet_h->pipefd[1]))) goto exit_fail2; knet_h->dst_host_filter = knet_handle_cfg->dst_host_filter; knet_h->dst_host_filter_fn = knet_handle_cfg->dst_host_filter_fn; if ((knet_h->dst_host_filter) && (!knet_h->dst_host_filter_fn)) goto exit_fail2; - if (crypto_init(knet_h, knet_handle_cfg) < 0) - goto exit_fail2; - if ((knet_h->tap_to_links_buf = malloc(KNET_DATABUFSIZE))== NULL) - goto exit_fail3; + goto exit_fail2; memset(knet_h->tap_to_links_buf, 0, KNET_DATABUFSIZE); if ((knet_h->recv_from_links_buf = malloc(KNET_DATABUFSIZE))== NULL) - goto exit_fail4; + goto exit_fail3; memset(knet_h->recv_from_links_buf, 0, KNET_DATABUFSIZE); if ((knet_h->pingbuf = malloc(KNET_PINGBUFSIZE))== NULL) - goto exit_fail5; + goto exit_fail4; memset(knet_h->pingbuf, 0, KNET_PINGBUFSIZE); if (pthread_rwlock_init(&knet_h->list_rwlock, NULL) != 0) - goto exit_fail6; + goto exit_fail5; knet_h->tap_to_links_epollfd = epoll_create(KNET_MAX_EVENTS); knet_h->recv_from_links_epollfd = epoll_create(KNET_MAX_EVENTS); knet_h->dst_link_handler_epollfd = epoll_create(KNET_MAX_EVENTS); if ((knet_h->tap_to_links_epollfd < 0) || (knet_h->recv_from_links_epollfd < 0) || (knet_h->dst_link_handler_epollfd < 0)) - goto exit_fail7; + goto exit_fail6; if ((_fdset_cloexec(knet_h->tap_to_links_epollfd) != 0) || (_fdset_cloexec(knet_h->recv_from_links_epollfd) != 0) || (_fdset_cloexec(knet_h->dst_link_handler_epollfd) != 0)) - goto exit_fail7; + goto exit_fail6; memset(&ev, 0, sizeof(struct epoll_event)); ev.events = EPOLLIN; ev.data.fd = knet_h->sockfd; if (epoll_ctl(knet_h->tap_to_links_epollfd, EPOLL_CTL_ADD, knet_h->sockfd, &ev) != 0) - goto exit_fail7; + goto exit_fail6; memset(&ev, 0, sizeof(struct epoll_event)); ev.events = EPOLLIN; ev.data.fd = knet_h->pipefd[0]; if (epoll_ctl(knet_h->dst_link_handler_epollfd, EPOLL_CTL_ADD, knet_h->pipefd[0], &ev) != 0) - goto exit_fail7; + goto exit_fail6; if (pthread_create(&knet_h->dst_link_handler_thread, 0, _handle_dst_link_handler_thread, (void *) knet_h) != 0) - goto exit_fail7; + goto exit_fail6; if (pthread_create(&knet_h->tap_to_links_thread, 0, _handle_tap_to_links_thread, (void *) knet_h) != 0) - goto exit_fail8; + goto exit_fail7; if (pthread_create(&knet_h->recv_from_links_thread, 0, _handle_recv_from_links_thread, (void *) knet_h) != 0) - goto exit_fail9; + goto exit_fail8; if (pthread_create(&knet_h->heartbt_thread, 0, _handle_heartbt_thread, (void *) knet_h) != 0) - goto exit_fail10; + goto exit_fail9; return knet_h; -exit_fail10: +exit_fail9: pthread_cancel(knet_h->recv_from_links_thread); -exit_fail9: +exit_fail8: pthread_cancel(knet_h->tap_to_links_thread); -exit_fail8: +exit_fail7: pthread_cancel(knet_h->dst_link_handler_thread); -exit_fail7: +exit_fail6: if (knet_h->tap_to_links_epollfd >= 0) close(knet_h->tap_to_links_epollfd); if (knet_h->recv_from_links_epollfd >= 0) close(knet_h->recv_from_links_epollfd); if (knet_h->dst_link_handler_epollfd >= 0) close(knet_h->dst_link_handler_epollfd); pthread_rwlock_destroy(&knet_h->list_rwlock); -exit_fail6: - free(knet_h->pingbuf); - exit_fail5: - free(knet_h->recv_from_links_buf); + free(knet_h->pingbuf); exit_fail4: - free(knet_h->tap_to_links_buf); + free(knet_h->recv_from_links_buf); exit_fail3: - crypto_fini(knet_h); + free(knet_h->tap_to_links_buf); exit_fail2: close(knet_h->pipefd[0]); close(knet_h->pipefd[1]); exit_fail1: free(knet_h); return NULL; } int knet_handle_free(knet_handle_t knet_h) { void *retval; if ((knet_h->host_head != NULL) || (knet_h->listener_head != NULL)) goto exit_busy; pthread_cancel(knet_h->heartbt_thread); pthread_join(knet_h->heartbt_thread, &retval); if (retval != PTHREAD_CANCELED) goto exit_busy; pthread_cancel(knet_h->tap_to_links_thread); pthread_join(knet_h->tap_to_links_thread, &retval); if (retval != PTHREAD_CANCELED) goto exit_busy; pthread_cancel(knet_h->recv_from_links_thread); pthread_join(knet_h->recv_from_links_thread, &retval); if (retval != PTHREAD_CANCELED) goto exit_busy; pthread_cancel(knet_h->dst_link_handler_thread); pthread_join(knet_h->dst_link_handler_thread, &retval); if (retval != PTHREAD_CANCELED) goto exit_busy; close(knet_h->tap_to_links_epollfd); close(knet_h->recv_from_links_epollfd); close(knet_h->dst_link_handler_epollfd); close(knet_h->pipefd[0]); close(knet_h->pipefd[1]); pthread_rwlock_destroy(&knet_h->list_rwlock); free(knet_h->tap_to_links_buf); free(knet_h->recv_from_links_buf); free(knet_h->pingbuf); crypto_fini(knet_h); free(knet_h); return 0; exit_busy: errno = EBUSY; return -EBUSY; } void knet_handle_setfwd(knet_handle_t knet_h, int enabled) { knet_h->enabled = (enabled == 1) ? 1 : 0; } +int knet_handle_crypto(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg) +{ + if (knet_h->enabled) + return -1; + + return crypto_init(knet_h, knet_handle_crypto_cfg); +} + void knet_link_timeout(struct knet_link *lnk, time_t interval, time_t timeout, int precision) { lnk->ping_interval = interval * 1000; /* microseconds */ lnk->pong_timeout = timeout * 1000; /* microseconds */ lnk->latency_fix = precision; lnk->latency_exp = precision - \ ((lnk->ping_interval * precision) / 8000000); } static void _handle_tap_to_links(knet_handle_t knet_h) { ssize_t inlen, len, outlen; struct knet_host *dst_host; int link_idx; uint16_t dst_host_ids[KNET_MAX_HOST]; size_t dst_host_ids_entries = 0; int bcast = 1; + unsigned char *outbuf = (unsigned char *)knet_h->tap_to_links_buf; inlen = read(knet_h->sockfd, knet_h->tap_to_links_buf->kf_data, KNET_DATABUFSIZE - (KNET_FRAME_SIZE + sizeof(seq_num_t))); if (inlen == 0) { /* TODO: disconnection, should never happen! */ return; } - len = inlen + KNET_FRAME_SIZE + sizeof(seq_num_t); + outlen = len = inlen + KNET_FRAME_SIZE + sizeof(seq_num_t); if (knet_h->enabled != 1) /* data forward is disabled */ return; if (knet_h->dst_host_filter) { bcast = knet_h->dst_host_filter_fn( (const unsigned char *)knet_h->tap_to_links_buf->kf_data, inlen, knet_h->tap_to_links_buf->kf_node, dst_host_ids, &dst_host_ids_entries); if (bcast < 0) return; if ((!bcast) && (!dst_host_ids_entries)) return; } if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0) return; if (!bcast) { int host_idx; for (host_idx = 0; host_idx < dst_host_ids_entries; host_idx++) { dst_host = knet_h->host_index[dst_host_ids[host_idx]]; if (!dst_host) continue; knet_h->tap_to_links_buf->kf_seq_num = htons(++dst_host->ucast_seq_num_tx); - if (crypto_encrypt_and_sign(knet_h->crypto_instance, - (const unsigned char *)knet_h->tap_to_links_buf, - len, - knet_h->tap_to_links_buf_crypt, - &outlen) < 0) { - pthread_rwlock_unlock(&knet_h->list_rwlock); - return; + if (knet_h->crypto_instance) { + if (crypto_encrypt_and_sign(knet_h->crypto_instance, + (const unsigned char *)knet_h->tap_to_links_buf, + len, + knet_h->tap_to_links_buf_crypt, + &outlen) < 0) { + pthread_rwlock_unlock(&knet_h->list_rwlock); + return; + } + outbuf = knet_h->tap_to_links_buf_crypt; } for (link_idx = 0; link_idx < dst_host->active_link_entries; link_idx++) { sendto(dst_host->link[dst_host->active_links[link_idx]].sock, - knet_h->tap_to_links_buf_crypt, outlen, MSG_DONTWAIT, + outbuf, outlen, MSG_DONTWAIT, (struct sockaddr *) &dst_host->link[dst_host->active_links[link_idx]].address, sizeof(struct sockaddr_storage)); if ((dst_host->link_handler_policy == KNET_LINK_POLICY_RR) && (dst_host->active_link_entries > 1)) { uint8_t cur_link_id = dst_host->active_links[0]; memmove(&dst_host->active_links[0], &dst_host->active_links[1], KNET_MAX_LINK - 1); dst_host->active_links[dst_host->active_link_entries - 1] = cur_link_id; break; } } } } else { knet_h->tap_to_links_buf->kf_seq_num = htons(++knet_h->bcast_seq_num_tx); - if (crypto_encrypt_and_sign(knet_h->crypto_instance, - (const unsigned char *)knet_h->tap_to_links_buf, - len, - knet_h->tap_to_links_buf_crypt, - &outlen) < 0) { - pthread_rwlock_unlock(&knet_h->list_rwlock); - return; + if (knet_h->crypto_instance) { + if (crypto_encrypt_and_sign(knet_h->crypto_instance, + (const unsigned char *)knet_h->tap_to_links_buf, + len, + knet_h->tap_to_links_buf_crypt, + &outlen) < 0) { + pthread_rwlock_unlock(&knet_h->list_rwlock); + return; + } + outbuf = knet_h->tap_to_links_buf_crypt; } for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) { for (link_idx = 0; link_idx < dst_host->active_link_entries; link_idx++) { sendto(dst_host->link[dst_host->active_links[link_idx]].sock, - knet_h->tap_to_links_buf_crypt, outlen, MSG_DONTWAIT, + outbuf, outlen, MSG_DONTWAIT, (struct sockaddr *) &dst_host->link[dst_host->active_links[link_idx]].address, sizeof(struct sockaddr_storage)); if ((dst_host->link_handler_policy == KNET_LINK_POLICY_RR) && (dst_host->active_link_entries > 1)) { uint8_t cur_link_id = dst_host->active_links[0]; memmove(&dst_host->active_links[0], &dst_host->active_links[1], KNET_MAX_LINK - 1); dst_host->active_links[dst_host->active_link_entries - 1] = cur_link_id; break; } } } } pthread_rwlock_unlock(&knet_h->list_rwlock); } static void _handle_recv_from_links(knet_handle_t knet_h, int sockfd) { ssize_t len, outlen; struct sockaddr_storage address; socklen_t addrlen; struct knet_host *src_host; struct knet_link *src_link; unsigned long long latency_last; uint16_t dst_host_ids[KNET_MAX_HOST]; size_t dst_host_ids_entries = 0; int bcast = 1; + unsigned char *outbuf = (unsigned char *)knet_h->recv_from_links_buf; if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0) return; addrlen = sizeof(struct sockaddr_storage); len = recvfrom(sockfd, knet_h->recv_from_links_buf, KNET_DATABUFSIZE, MSG_DONTWAIT, (struct sockaddr *) &address, &addrlen); - if (crypto_authenticate_and_decrypt(knet_h->crypto_instance, - (unsigned char *)knet_h->recv_from_links_buf, - &len) < 0) - goto exit_unlock; + if (knet_h->crypto_instance) { + if (crypto_authenticate_and_decrypt(knet_h->crypto_instance, + (unsigned char *)knet_h->recv_from_links_buf, + &len) < 0) + goto exit_unlock; + } if (len < (KNET_FRAME_SIZE + 1)) goto exit_unlock; if (ntohl(knet_h->recv_from_links_buf->kf_magic) != KNET_FRAME_MAGIC) goto exit_unlock; if (knet_h->recv_from_links_buf->kf_version != KNET_FRAME_VERSION) goto exit_unlock; knet_h->recv_from_links_buf->kf_node = ntohs(knet_h->recv_from_links_buf->kf_node); src_host = knet_h->host_index[knet_h->recv_from_links_buf->kf_node]; if (src_host == NULL) { /* host not found */ goto exit_unlock; } src_link = NULL; if ((knet_h->recv_from_links_buf->kf_type & KNET_FRAME_PMSK) != 0) { src_link = src_host->link + (knet_h->recv_from_links_buf->kf_link % KNET_MAX_LINK); } switch (knet_h->recv_from_links_buf->kf_type) { case KNET_FRAME_DATA: if (knet_h->enabled != 1) /* data forward is disabled */ break; knet_h->recv_from_links_buf->kf_seq_num = ntohs(knet_h->recv_from_links_buf->kf_seq_num); if (knet_h->dst_host_filter) { int host_idx; int found = 0; bcast = knet_h->dst_host_filter_fn( (const unsigned char *)knet_h->recv_from_links_buf->kf_data, len, knet_h->recv_from_links_buf->kf_node, dst_host_ids, &dst_host_ids_entries); if (bcast < 0) goto exit_unlock; if ((!bcast) && (!dst_host_ids_entries)) goto exit_unlock; /* check if we are dst for this packet */ if (!bcast) { for (host_idx = 0; host_idx < dst_host_ids_entries; host_idx++) { if (dst_host_ids[host_idx] == knet_h->node_id) { found = 1; break; } } if (!found) goto exit_unlock; } } if (!knet_should_deliver(src_host, bcast, knet_h->recv_from_links_buf->kf_seq_num)) goto exit_unlock; if (write(knet_h->sockfd, knet_h->recv_from_links_buf->kf_data, len - (KNET_FRAME_SIZE + sizeof(seq_num_t))) == len - (KNET_FRAME_SIZE + sizeof(seq_num_t))) knet_has_been_delivered(src_host, bcast, knet_h->recv_from_links_buf->kf_seq_num); break; case KNET_FRAME_PING: + outlen = KNET_PINGBUFSIZE; knet_h->recv_from_links_buf->kf_type = KNET_FRAME_PONG; knet_h->recv_from_links_buf->kf_node = htons(knet_h->node_id); - if (crypto_encrypt_and_sign(knet_h->crypto_instance, - (const unsigned char *)knet_h->recv_from_links_buf, - len, - knet_h->recv_from_links_buf_crypt, - &outlen) < 0) - break; + if (knet_h->crypto_instance) { + if (crypto_encrypt_and_sign(knet_h->crypto_instance, + (const unsigned char *)knet_h->recv_from_links_buf, + len, + knet_h->recv_from_links_buf_crypt, + &outlen) < 0) + break; - sendto(src_link->sock, knet_h->recv_from_links_buf_crypt, outlen, MSG_DONTWAIT, + outbuf = knet_h->recv_from_links_buf_crypt; + } + + sendto(src_link->sock, outbuf, outlen, MSG_DONTWAIT, (struct sockaddr *) &src_link->address, sizeof(struct sockaddr_storage)); break; case KNET_FRAME_PONG: clock_gettime(CLOCK_MONOTONIC, &src_link->pong_last); timespec_diff(knet_h->recv_from_links_buf->kf_time, src_link->pong_last, &latency_last); src_link->latency = ((src_link->latency * src_link->latency_exp) + ((latency_last / 1000llu) * (src_link->latency_fix - src_link->latency_exp))) / src_link->latency_fix; if (src_link->latency < src_link->pong_timeout) { if (!src_link->connected) { int write_retry = 0; src_link->connected = 1; try_again: if (write(knet_h->pipefd[1], &src_host->node_id, sizeof(src_host->node_id)) != sizeof(src_host->node_id)) { if ((write_retry < 10) && ((errno = EAGAIN) || (errno = EWOULDBLOCK))) { write_retry++; goto try_again; } /* define what to do if we can't add a link */ } } } break; default: goto exit_unlock; } exit_unlock: pthread_rwlock_unlock(&knet_h->list_rwlock); } static void _handle_dst_link_updates(knet_handle_t knet_h) { uint16_t dst_host_id; struct knet_host *dst_host; int link_idx; int best_priority = -1; if (read(knet_h->pipefd[0], &dst_host_id, sizeof(dst_host_id)) != sizeof(dst_host_id)) return; if (pthread_rwlock_wrlock(&knet_h->list_rwlock) != 0) return; dst_host = knet_h->host_index[dst_host_id]; if (!dst_host) goto out_unlock; dst_host->active_link_entries = 0; for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) { if (dst_host->link[link_idx].configured != 1) /* link is not configured */ continue; if (dst_host->link[link_idx].connected != 1) /* link is not enabled */ continue; if (dst_host->link_handler_policy == KNET_LINK_POLICY_PASSIVE) { /* for passive we look for the only active link with higher priority */ if (dst_host->link[link_idx].priority > best_priority) { dst_host->active_links[0] = link_idx; best_priority = dst_host->link[link_idx].priority; } dst_host->active_link_entries = 1; } else { /* for RR and ACTIVE we need to copy all available links */ dst_host->active_links[dst_host->active_link_entries] = link_idx; dst_host->active_link_entries++; } } /* no active links, we can clean the circular buffers and indexes */ if (!dst_host->active_link_entries) { memset(dst_host->bcast_circular_buffer, 0, KNET_CBUFFER_SIZE); memset(dst_host->ucast_circular_buffer, 0, KNET_CBUFFER_SIZE); dst_host->bcast_seq_num_rx = 0; dst_host->ucast_seq_num_rx = 0; } out_unlock: pthread_rwlock_unlock(&knet_h->list_rwlock); return; } static void _handle_check_each(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link) { int len; - ssize_t outlen; + ssize_t outlen = KNET_PINGBUFSIZE; struct timespec clock_now, pong_last; unsigned long long diff_ping; + unsigned char *outbuf = (unsigned char *)knet_h->pingbuf; /* caching last pong to avoid race conditions */ pong_last = dst_link->pong_last; if (clock_gettime(CLOCK_MONOTONIC, &clock_now) != 0) return; timespec_diff(dst_link->ping_last, clock_now, &diff_ping); if (diff_ping >= (dst_link->ping_interval * 1000llu)) { knet_h->pingbuf->kf_time = clock_now; knet_h->pingbuf->kf_link = dst_link->link_id; - if (crypto_encrypt_and_sign(knet_h->crypto_instance, - (const unsigned char *)knet_h->pingbuf, - KNET_PINGBUFSIZE, - knet_h->pingbuf_crypt, - &outlen) < 0) - return; + if (knet_h->crypto_instance) { + if (crypto_encrypt_and_sign(knet_h->crypto_instance, + (const unsigned char *)knet_h->pingbuf, + KNET_PINGBUFSIZE, + knet_h->pingbuf_crypt, + &outlen) < 0) + return; + + outbuf = knet_h->pingbuf_crypt; + } - len = sendto(dst_link->sock, knet_h->pingbuf_crypt, outlen, + len = sendto(dst_link->sock, outbuf, outlen, MSG_DONTWAIT, (struct sockaddr *) &dst_link->address, sizeof(struct sockaddr_storage)); if (len == outlen) dst_link->ping_last = clock_now; } if (dst_link->connected == 1) { timespec_diff(pong_last, clock_now, &diff_ping); if (diff_ping >= (dst_link->pong_timeout * 1000llu)) { int write_retry = 0; dst_link->connected = 0; try_again: if (write(knet_h->pipefd[1], &dst_host->node_id, sizeof(dst_host->node_id)) != sizeof(dst_host->node_id)) { if ((write_retry < 10) && ((errno = EAGAIN) || (errno = EWOULDBLOCK))) { write_retry++; goto try_again; } /* define what to do if we can't deactivate a link */ } } } } static void *_handle_heartbt_thread(void *data) { knet_handle_t knet_h; struct knet_host *dst_host; int link_idx; knet_h = (knet_handle_t) data; /* preparing ping buffer */ knet_h->pingbuf->kf_magic = htonl(KNET_FRAME_MAGIC); knet_h->pingbuf->kf_version = KNET_FRAME_VERSION; knet_h->pingbuf->kf_type = KNET_FRAME_PING; knet_h->pingbuf->kf_node = htons(knet_h->node_id); while (1) { usleep(KNET_PING_TIMERES); if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0) continue; for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) { for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) { if (dst_host->link[link_idx].configured != 1) continue; _handle_check_each(knet_h, dst_host, &dst_host->link[link_idx]); } } pthread_rwlock_unlock(&knet_h->list_rwlock); } return NULL; } static void *_handle_tap_to_links_thread(void *data) { knet_handle_t knet_h; struct epoll_event events[KNET_MAX_EVENTS]; knet_h = (knet_handle_t) data; /* preparing data buffer */ knet_h->tap_to_links_buf->kf_magic = htonl(KNET_FRAME_MAGIC); knet_h->tap_to_links_buf->kf_version = KNET_FRAME_VERSION; knet_h->tap_to_links_buf->kf_type = KNET_FRAME_DATA; knet_h->tap_to_links_buf->kf_node = htons(knet_h->node_id); while (1) { if (epoll_wait(knet_h->tap_to_links_epollfd, events, KNET_MAX_EVENTS, -1) >= 1) _handle_tap_to_links(knet_h); } return NULL; } static void *_handle_recv_from_links_thread(void *data) { int i, nev; knet_handle_t knet_h = (knet_handle_t) data; struct epoll_event events[KNET_MAX_EVENTS]; while (1) { nev = epoll_wait(knet_h->recv_from_links_epollfd, events, KNET_MAX_EVENTS, -1); for (i = 0; i < nev; i++) { _handle_recv_from_links(knet_h, events[i].data.fd); } } return NULL; } static void *_handle_dst_link_handler_thread(void *data) { knet_handle_t knet_h = (knet_handle_t) data; struct epoll_event events[KNET_MAX_EVENTS]; while (1) { if (epoll_wait(knet_h->dst_link_handler_epollfd, events, KNET_MAX_EVENTS, -1) >= 1) _handle_dst_link_updates(knet_h); } return NULL; } diff --git a/libknet/libknet-private.h b/libknet/libknet-private.h index 7c95894e..5741cbf2 100644 --- a/libknet/libknet-private.h +++ b/libknet/libknet-private.h @@ -1,61 +1,61 @@ #ifndef __LIBKNET_PRIVATE_H__ #define __LIBKNET_PRIVATE_H__ /* * NOTE: you shouldn't need to include this header normally */ #include "libknet.h" #define KNET_DATABUFSIZE 131072 /* 128k */ #define KNET_PINGBUFSIZE sizeof(struct knet_frame) #define timespec_diff(start, end, diff) \ do { \ if (end.tv_sec > start.tv_sec) \ *(diff) = ((end.tv_sec - start.tv_sec) * 1000000000llu) \ + end.tv_nsec - start.tv_nsec; \ else \ *(diff) = end.tv_nsec - start.tv_nsec; \ } while (0); struct knet_handle { uint16_t node_id; unsigned int enabled:1; int sockfd; int pipefd[2]; int tap_to_links_epollfd; int recv_from_links_epollfd; int dst_link_handler_epollfd; struct knet_host *host_head; struct knet_host *host_tail; struct knet_host *host_index[KNET_MAX_HOST]; struct knet_listener *listener_head; struct knet_frame *tap_to_links_buf; - unsigned char *tap_to_links_buf_crypt; struct knet_frame *recv_from_links_buf; - unsigned char *recv_from_links_buf_crypt; struct knet_frame *pingbuf; - unsigned char *pingbuf_crypt; pthread_t tap_to_links_thread; pthread_t recv_from_links_thread; pthread_t heartbt_thread; pthread_t dst_link_handler_thread; pthread_rwlock_t list_rwlock; struct crypto_instance *crypto_instance; + unsigned char *tap_to_links_buf_crypt; + unsigned char *recv_from_links_buf_crypt; + unsigned char *pingbuf_crypt; seq_num_t bcast_seq_num_tx; uint8_t dst_host_filter; int (*dst_host_filter_fn) ( const unsigned char *outdata, ssize_t outdata_len, uint16_t src_node_id, uint16_t *dst_host_ids, size_t *dst_host_ids_entries); }; int _fdset_cloexec(int fd); int _fdset_nonblock(int fd); int knet_should_deliver(struct knet_host *host, int bcast, seq_num_t seq_num); void knet_has_been_delivered(struct knet_host *host, int bcast, seq_num_t seq_num); #endif diff --git a/libknet/libknet.h b/libknet/libknet.h index 2c4ac463..7c2edade 100644 --- a/libknet/libknet.h +++ b/libknet/libknet.h @@ -1,171 +1,177 @@ #ifndef __LIBKNET_H__ #define __LIBKNET_H__ #include #include typedef struct knet_handle *knet_handle_t; #define KNET_RING_DEFPORT 50000 #define KNET_RING_RCVBUFF 8388608 #define KNET_MAX_HOST 65536 #define KNET_MAX_LINK 8 #define KNET_MAX_HOST_LEN 64 #define KNET_CBUFFER_SIZE 4096 /* typedef uint64_t seq_num_t; #define SEQ_MAX UINT64_MAX */ typedef uint16_t seq_num_t; #define SEQ_MAX UINT16_MAX struct knet_link { uint8_t link_id; int sock; char ipaddr[KNET_MAX_HOST_LEN]; char port[6]; struct sockaddr_storage address; unsigned int configured:1; /* link is configured and ready to be used */ unsigned int connected:1; /* link is enabled for data */ uint8_t priority; /* higher priority == preferred for A/P */ unsigned long long latency; /* average latency computed by fix/exp */ unsigned int latency_exp; unsigned int latency_fix; unsigned long long ping_interval; unsigned long long pong_timeout; struct timespec ping_last; struct timespec pong_last; }; #define KNET_LINK_POLICY_PASSIVE 0 #define KNET_LINK_POLICY_ACTIVE 1 #define KNET_LINK_POLICY_RR 2 struct knet_host { uint16_t node_id; char name[KNET_MAX_HOST_LEN]; char bcast_circular_buffer[KNET_CBUFFER_SIZE]; seq_num_t bcast_seq_num_rx; char ucast_circular_buffer[KNET_CBUFFER_SIZE]; seq_num_t ucast_seq_num_tx; seq_num_t ucast_seq_num_rx; struct knet_listener *listener; struct knet_link link[KNET_MAX_LINK]; uint8_t active_link_entries; uint8_t active_links[KNET_MAX_LINK]; uint8_t link_handler_policy; struct knet_host *next; }; struct knet_listener { int sock; char ipaddr[KNET_MAX_HOST_LEN]; char port[6]; struct sockaddr_storage address; struct knet_listener *next; }; union knet_frame_data { struct { seq_num_t kfd_seq_num; uint8_t kfd_data[0]; } data; struct { uint8_t kfd_link; struct timespec kfd_time; } ping; } __attribute__((packed)); struct knet_frame { uint32_t kf_magic; uint8_t kf_version; uint8_t kf_type; uint16_t kf_node; union knet_frame_data kf_payload; } __attribute__((packed)); #define kf_seq_num kf_payload.data.kfd_seq_num #define kf_data kf_payload.data.kfd_data #define kf_link kf_payload.ping.kfd_link #define kf_time kf_payload.ping.kfd_time #define KNET_FRAME_SIZE (sizeof(struct knet_frame) - sizeof(union knet_frame_data)) #define KNET_FRAME_MAGIC 0x12344321 #define KNET_FRAME_VERSION 0x01 #define KNET_FRAME_DATA 0x00 #define KNET_FRAME_PING 0x81 #define KNET_FRAME_PONG 0x82 #define KNET_FRAME_PMSK 0x80 /* ping/pong packet mask */ #define KNET_MIN_KEY_LEN 1024 #define KNET_MAX_KEY_LEN 4096 #define KNET_DST_FILTER_DISABLE 0 /* pckt goes everywhere */ #define KNET_DST_FILTER_ENABLE 1 /* pckt goes via dst_host_filter, see knet_ether_filter for example */ /* * dst_host_filter_fn should return * -1 on error, pkt is discarded * 0 all good, send pkt to dst_host_ids and there are dst_host_ids_entries in buffer ready * 1 send it to all hosts. contents of dst_host_ids and dst_host_ids_entries is ignored. */ struct knet_handle_cfg { int fd; uint16_t node_id; - char *crypto_cipher_type; - char *crypto_hash_type; - unsigned char *private_key; - unsigned int private_key_len; uint8_t dst_host_filter; int (*dst_host_filter_fn) ( const unsigned char *outdata, ssize_t outdata_len, uint16_t src_node_id, uint16_t *dst_host_ids, size_t *dst_host_ids_entries); }; int ether_host_filter_fn (const unsigned char *outdata, ssize_t outdata_len, uint16_t src_node_id, uint16_t *dst_host_ids, size_t *dst_host_ids_entries); knet_handle_t knet_handle_new(const struct knet_handle_cfg *knet_handle_cfg); void knet_handle_setfwd(knet_handle_t knet_h, int enabled); int knet_handle_free(knet_handle_t knet_h); +struct knet_handle_crypto_cfg { + char crypto_model[16]; + char crypto_cipher_type[16]; + char crypto_hash_type[16]; + unsigned char private_key[KNET_MAX_KEY_LEN]; + unsigned int private_key_len; +}; + +int knet_handle_crypto(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg); + int knet_host_add(knet_handle_t knet_h, uint16_t node_id); int knet_host_acquire(knet_handle_t knet_h, struct knet_host **host); int knet_host_get(knet_handle_t knet_h, uint16_t node_id, struct knet_host **host); int knet_host_release(knet_handle_t knet_h, struct knet_host **host); int knet_host_remove(knet_handle_t knet_h, uint16_t node_id); int knet_host_dst_cache_update(knet_handle_t knet_h, uint16_t node_id); void knet_link_timeout(struct knet_link *lnk, time_t interval, time_t timeout, int precision); #define KNET_HOST_FOREACH_NEXT 0 /* next host */ #define KNET_HOST_FOREACH_FOUND 1 /* host found, exit loop */ struct knet_host_search { int param1; /* user parameter 1 */ void *data1; /* user data pointer 1 */ void *data2; /* user data pointer 2 */ int retval; /* search return value */ }; typedef int (*knet_link_fn_t)(knet_handle_t knet_h, struct knet_host *host, struct knet_host_search *data); int knet_host_foreach(knet_handle_t knet_h, knet_link_fn_t linkfun, struct knet_host_search *data); int knet_listener_acquire(knet_handle_t knet_h, struct knet_listener **head, int writelock); int knet_listener_release(knet_handle_t knet_h); int knet_listener_add(knet_handle_t knet_h, struct knet_listener *listener); int knet_listener_remove(knet_handle_t knet_h, struct knet_listener *listener); #endif diff --git a/libknet/nsscrypto.c b/libknet/nsscrypto.c index dc28b0aa..14ca3c05 100644 --- a/libknet/nsscrypto.c +++ b/libknet/nsscrypto.c @@ -1,600 +1,600 @@ #include "config.h" #include #include #include #include #include #include #include "nsscrypto.h" #include "libknet-private.h" #ifdef CRYPTO_DEBUG #define log_printf(format, args...) fprintf(stderr, format "\n", ##args); #else #define log_printf(format, args...); #endif /* * crypto definitions and conversion tables */ #define SALT_SIZE 16 #define KNET_DATABUFSIZE_CRYPT KNET_DATABUFSIZE * 2 enum crypto_crypt_t { CRYPTO_CIPHER_TYPE_NONE = 0, CRYPTO_CIPHER_TYPE_AES256 = 1 }; CK_MECHANISM_TYPE cipher_to_nss[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ CKM_AES_CBC_PAD /* CRYPTO_CIPHER_TYPE_AES256 */ }; size_t cipher_key_len[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ 32, /* CRYPTO_CIPHER_TYPE_AES256 */ }; size_t cypher_block_len[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ AES_BLOCK_SIZE /* CRYPTO_CIPHER_TYPE_AES256 */ }; /* * hash definitions and conversion tables */ enum crypto_hash_t { CRYPTO_HASH_TYPE_NONE = 0, CRYPTO_HASH_TYPE_MD5 = 1, CRYPTO_HASH_TYPE_SHA1 = 2, CRYPTO_HASH_TYPE_SHA256 = 3, CRYPTO_HASH_TYPE_SHA384 = 4, CRYPTO_HASH_TYPE_SHA512 = 5 }; CK_MECHANISM_TYPE hash_to_nss[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ CKM_MD5_HMAC, /* CRYPTO_HASH_TYPE_MD5 */ CKM_SHA_1_HMAC, /* CRYPTO_HASH_TYPE_SHA1 */ CKM_SHA256_HMAC, /* CRYPTO_HASH_TYPE_SHA256 */ CKM_SHA384_HMAC, /* CRYPTO_HASH_TYPE_SHA384 */ CKM_SHA512_HMAC /* CRYPTO_HASH_TYPE_SHA512 */ }; size_t hash_len[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ MD5_LENGTH, /* CRYPTO_HASH_TYPE_MD5 */ SHA1_LENGTH, /* CRYPTO_HASH_TYPE_SHA1 */ SHA256_LENGTH, /* CRYPTO_HASH_TYPE_SHA256 */ SHA384_LENGTH, /* CRYPTO_HASH_TYPE_SHA384 */ SHA512_LENGTH /* CRYPTO_HASH_TYPE_SHA512 */ }; size_t hash_block_len[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ MD5_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_MD5 */ SHA1_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_SHA1 */ SHA256_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_SHA256 */ SHA384_BLOCK_LENGTH, /* CRYPTO_HASH_TYPE_SHA384 */ SHA512_BLOCK_LENGTH /* CRYPTO_HASH_TYPE_SHA512 */ }; struct crypto_instance { PK11SymKey *nss_sym_key; PK11SymKey *nss_sym_key_sign; unsigned char *private_key; unsigned int private_key_len; int crypto_cipher_type; int crypto_hash_type; }; /* * crypt/decrypt functions */ static int string_to_crypto_cipher_type(const char* crypto_cipher_type) { if (strcmp(crypto_cipher_type, "none") == 0) { return CRYPTO_CIPHER_TYPE_NONE; } else if (strcmp(crypto_cipher_type, "aes256") == 0) { return CRYPTO_CIPHER_TYPE_AES256; } return -1; } static int init_nss_crypto(struct crypto_instance *instance) { PK11SlotInfo* crypt_slot = NULL; SECItem crypt_param; if (!cipher_to_nss[instance->crypto_cipher_type]) { return 0; } crypt_param.type = siBuffer; crypt_param.data = instance->private_key; crypt_param.len = cipher_key_len[instance->crypto_cipher_type]; crypt_slot = PK11_GetBestSlot(cipher_to_nss[instance->crypto_cipher_type], NULL); if (crypt_slot == NULL) { log_printf("Unable to find security slot (err %d)", PR_GetError()); return -1; } instance->nss_sym_key = PK11_ImportSymKey(crypt_slot, cipher_to_nss[instance->crypto_cipher_type], PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT, &crypt_param, NULL); if (instance->nss_sym_key == NULL) { log_printf("Failure to import key into NSS (err %d)", PR_GetError()); return -1; } PK11_FreeSlot(crypt_slot); return 0; } static int encrypt_nss( struct crypto_instance *instance, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len) { PK11Context* crypt_context = NULL; SECItem crypt_param; SECItem *nss_sec_param = NULL; int tmp1_outlen = 0; unsigned int tmp2_outlen = 0; unsigned char *salt = buf_out; unsigned char *data = buf_out + SALT_SIZE; int err = -1; if (PK11_GenerateRandom (salt, SALT_SIZE) != SECSuccess) { log_printf("Failure to generate a random number %d", PR_GetError()); goto out; } crypt_param.type = siBuffer; crypt_param.data = salt; crypt_param.len = SALT_SIZE; nss_sec_param = PK11_ParamFromIV (cipher_to_nss[instance->crypto_cipher_type], &crypt_param); if (nss_sec_param == NULL) { log_printf("Failure to set up PKCS11 param (err %d)", PR_GetError()); goto out; } /* * Create cipher context for encryption */ crypt_context = PK11_CreateContextBySymKey (cipher_to_nss[instance->crypto_cipher_type], CKA_ENCRYPT, instance->nss_sym_key, nss_sec_param); if (!crypt_context) { log_printf("PK11_CreateContext failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } if (PK11_CipherOp(crypt_context, data, &tmp1_outlen, KNET_DATABUFSIZE_CRYPT, (unsigned char *)buf_in, buf_in_len) != SECSuccess) { log_printf("PK11_CipherOp failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } if (PK11_DigestFinal(crypt_context, data + tmp1_outlen, &tmp2_outlen, KNET_DATABUFSIZE_CRYPT - tmp1_outlen) != SECSuccess) { log_printf("PK11_DigestFinal failed (encrypt) crypt_type=%d (err %d)", (int)cipher_to_nss[instance->crypto_cipher_type], PR_GetError()); goto out; } *buf_out_len = tmp1_outlen + tmp2_outlen + SALT_SIZE; err = 0; out: if (crypt_context) { PK11_DestroyContext(crypt_context, PR_TRUE); } if (nss_sec_param) { SECITEM_FreeItem(nss_sec_param, PR_TRUE); } return err; } static int decrypt_nss ( struct crypto_instance *instance, unsigned char *buf, ssize_t *buf_len) { PK11Context* decrypt_context = NULL; SECItem decrypt_param; int tmp1_outlen = 0; unsigned int tmp2_outlen = 0; unsigned char *salt = buf; unsigned char *data = salt + SALT_SIZE; int datalen = *buf_len - SALT_SIZE; unsigned char outbuf[KNET_DATABUFSIZE_CRYPT]; int outbuf_len; int err = -1; /* Create cipher context for decryption */ decrypt_param.type = siBuffer; decrypt_param.data = salt; decrypt_param.len = SALT_SIZE; decrypt_context = PK11_CreateContextBySymKey(cipher_to_nss[instance->crypto_cipher_type], CKA_DECRYPT, instance->nss_sym_key, &decrypt_param); if (!decrypt_context) { log_printf("PK11_CreateContext (decrypt) failed (err %d)", PR_GetError()); goto out; } if (PK11_CipherOp(decrypt_context, outbuf, &tmp1_outlen, sizeof(outbuf), data, datalen) != SECSuccess) { log_printf("PK11_CipherOp (decrypt) failed (err %d)", PR_GetError()); goto out; } if (PK11_DigestFinal(decrypt_context, outbuf + tmp1_outlen, &tmp2_outlen, sizeof(outbuf) - tmp1_outlen) != SECSuccess) { log_printf("PK11_DigestFinal (decrypt) failed (err %d)", PR_GetError()); goto out; } outbuf_len = tmp1_outlen + tmp2_outlen; memset(buf, 0, *buf_len); memcpy(buf, outbuf, outbuf_len); *buf_len = outbuf_len; err = 0; out: if (decrypt_context) { PK11_DestroyContext(decrypt_context, PR_TRUE); } return err; } /* * hash/hmac/digest functions */ static int string_to_crypto_hash_type(const char* crypto_hash_type) { if (strcmp(crypto_hash_type, "none") == 0) { return CRYPTO_HASH_TYPE_NONE; } else if (strcmp(crypto_hash_type, "md5") == 0) { return CRYPTO_HASH_TYPE_MD5; } else if (strcmp(crypto_hash_type, "sha1") == 0) { return CRYPTO_HASH_TYPE_SHA1; } else if (strcmp(crypto_hash_type, "sha256") == 0) { return CRYPTO_HASH_TYPE_SHA256; } else if (strcmp(crypto_hash_type, "sha384") == 0) { return CRYPTO_HASH_TYPE_SHA384; } else if (strcmp(crypto_hash_type, "sha512") == 0) { return CRYPTO_HASH_TYPE_SHA512; } return -1; } static int init_nss_hash(struct crypto_instance *instance) { PK11SlotInfo* hash_slot = NULL; SECItem hash_param; if (!hash_to_nss[instance->crypto_hash_type]) { return 0; } hash_param.type = siBuffer; hash_param.data = 0; hash_param.len = 0; hash_slot = PK11_GetBestSlot(hash_to_nss[instance->crypto_hash_type], NULL); if (hash_slot == NULL) { log_printf("Unable to find security slot (err %d)", PR_GetError()); return -1; } instance->nss_sym_key_sign = PK11_ImportSymKey(hash_slot, hash_to_nss[instance->crypto_hash_type], PK11_OriginUnwrap, CKA_SIGN, &hash_param, NULL); if (instance->nss_sym_key_sign == NULL) { log_printf("Failure to import key into NSS (err %d)", PR_GetError()); return -1; } PK11_FreeSlot(hash_slot); return 0; } static int calculate_nss_hash( struct crypto_instance *instance, const unsigned char *buf, const size_t buf_len, unsigned char *hash) { PK11Context* hash_context = NULL; SECItem hash_param; unsigned int hash_tmp_outlen = 0; unsigned char hash_block[hash_block_len[instance->crypto_hash_type]]; int err = -1; /* Now do the digest */ hash_param.type = siBuffer; hash_param.data = 0; hash_param.len = 0; hash_context = PK11_CreateContextBySymKey(hash_to_nss[instance->crypto_hash_type], CKA_SIGN, instance->nss_sym_key_sign, &hash_param); if (!hash_context) { log_printf("PK11_CreateContext failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestBegin(hash_context) != SECSuccess) { log_printf("PK11_DigestBegin failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestOp(hash_context, buf, buf_len) != SECSuccess) { log_printf("PK11_DigestOp failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } if (PK11_DigestFinal(hash_context, hash_block, &hash_tmp_outlen, hash_block_len[instance->crypto_hash_type]) != SECSuccess) { log_printf("PK11_DigestFinale failed (hash) hash_type=%d (err %d)", (int)hash_to_nss[instance->crypto_hash_type], PR_GetError()); goto out; } memcpy(hash, hash_block, hash_len[instance->crypto_hash_type]); err = 0; out: if (hash_context) { PK11_DestroyContext(hash_context, PR_TRUE); } return err; } /* * global/glue nss functions */ static int init_nss_db(struct crypto_instance *instance) { if ((!cipher_to_nss[instance->crypto_cipher_type]) && (!hash_to_nss[instance->crypto_hash_type])) { return 0; } if (NSS_NoDB_Init(".") != SECSuccess) { log_printf("NSS DB initialization failed (err %d)", PR_GetError()); return -1; } return 0; } static int init_nss(struct crypto_instance *instance) { if (init_nss_db(instance) < 0) { return -1; } if (init_nss_crypto(instance) < 0) { return -1; } if (init_nss_hash(instance) < 0) { return -1; } return 0; } /* * exported API */ int crypto_encrypt_and_sign ( struct crypto_instance *instance, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len) { if (cipher_to_nss[instance->crypto_cipher_type]) { if (encrypt_nss(instance, buf_in, buf_in_len, buf_out, buf_out_len) < 0) { return -1; } } else { memcpy(buf_out, buf_in, buf_in_len); *buf_out_len = buf_in_len; } if (hash_to_nss[instance->crypto_hash_type]) { if (calculate_nss_hash(instance, buf_out, *buf_out_len, buf_out + *buf_out_len) < 0) { return -1; } *buf_out_len = *buf_out_len + hash_len[instance->crypto_hash_type]; } return 0; } int crypto_authenticate_and_decrypt (struct crypto_instance *instance, unsigned char *buf, ssize_t *buf_len) { if (hash_to_nss[instance->crypto_hash_type]) { unsigned char tmp_hash[hash_len[instance->crypto_hash_type]]; if (calculate_nss_hash(instance, buf, *buf_len - hash_len[instance->crypto_hash_type], tmp_hash) < 0) { return -1; } if (memcmp(tmp_hash, buf + (*buf_len - hash_len[instance->crypto_hash_type]), hash_len[instance->crypto_hash_type]) != 0) { log_printf("Digest does not match"); return -1; } *buf_len = *buf_len - hash_len[instance->crypto_hash_type]; } if (cipher_to_nss[instance->crypto_cipher_type]) { if (decrypt_nss(instance, buf, buf_len) < 0) { return -1; } } return 0; } int crypto_init( knet_handle_t knet_h, - const struct knet_handle_cfg *knet_handle_cfg) + struct knet_handle_crypto_cfg *knet_handle_crypto_cfg) { - log_printf("Initizializing crypto module [%s/%s]", - knet_handle_cfg->crypto_cipher_type, - knet_handle_cfg->crypto_hash_type); + log_printf("Initizializing nss crypto module [%s/%s]", + knet_handle_crypto_cfg->crypto_cipher_type, + knet_handle_crypto_cfg->crypto_hash_type); knet_h->crypto_instance = malloc(sizeof(struct crypto_instance)); if (!knet_h->crypto_instance) { return -1; } memset(knet_h->crypto_instance, 0, sizeof(struct crypto_instance)); - if (!knet_handle_cfg->crypto_cipher_type) { + if (!knet_handle_crypto_cfg->crypto_cipher_type) { goto out_err; } - knet_h->crypto_instance->crypto_cipher_type = string_to_crypto_cipher_type(knet_handle_cfg->crypto_cipher_type); + knet_h->crypto_instance->crypto_cipher_type = string_to_crypto_cipher_type(knet_handle_crypto_cfg->crypto_cipher_type); if (knet_h->crypto_instance->crypto_cipher_type < 0) { goto out_err; } - if (!knet_handle_cfg->crypto_hash_type) { + if (!knet_handle_crypto_cfg->crypto_hash_type) { goto out_err; } - knet_h->crypto_instance->crypto_hash_type = string_to_crypto_hash_type(knet_handle_cfg->crypto_hash_type); + knet_h->crypto_instance->crypto_hash_type = string_to_crypto_hash_type(knet_handle_crypto_cfg->crypto_hash_type); if (knet_h->crypto_instance->crypto_hash_type < 0) { goto out_err; } - knet_h->crypto_instance->private_key = knet_handle_cfg->private_key; - knet_h->crypto_instance->private_key_len = knet_handle_cfg->private_key_len; + knet_h->crypto_instance->private_key = knet_handle_crypto_cfg->private_key; + knet_h->crypto_instance->private_key_len = knet_handle_crypto_cfg->private_key_len; if ((knet_h->crypto_instance->crypto_cipher_type > 0) || (knet_h->crypto_instance->crypto_hash_type > 0)) { if ((!knet_h->crypto_instance->private_key) || (knet_h->crypto_instance->private_key_len < KNET_MIN_KEY_LEN) || (knet_h->crypto_instance->private_key_len > KNET_MAX_KEY_LEN)) { goto out_err; } } knet_h->tap_to_links_buf_crypt = malloc(KNET_DATABUFSIZE_CRYPT); if (!knet_h->tap_to_links_buf_crypt) goto out_err; knet_h->pingbuf_crypt = malloc(KNET_DATABUFSIZE_CRYPT); if (!knet_h->pingbuf_crypt) goto out_err; knet_h->recv_from_links_buf_crypt = malloc(KNET_DATABUFSIZE_CRYPT); if (!knet_h->recv_from_links_buf_crypt) goto out_err; - knet_h->crypto_instance->private_key = knet_handle_cfg->private_key; - knet_h->crypto_instance->private_key_len = knet_handle_cfg->private_key_len; + knet_h->crypto_instance->private_key = knet_handle_crypto_cfg->private_key; + knet_h->crypto_instance->private_key_len = knet_handle_crypto_cfg->private_key_len; if (init_nss(knet_h->crypto_instance) < 0) { goto out_err; } return 0; out_err: crypto_fini(knet_h); return -1; } void crypto_fini( knet_handle_t knet_h) { if (knet_h->crypto_instance) { if (knet_h->crypto_instance->nss_sym_key) PK11_FreeSymKey(knet_h->crypto_instance->nss_sym_key); if (knet_h->crypto_instance->nss_sym_key_sign) PK11_FreeSymKey(knet_h->crypto_instance->nss_sym_key_sign); if (knet_h->pingbuf_crypt) free(knet_h->pingbuf_crypt); if (knet_h->tap_to_links_buf_crypt) free(knet_h->tap_to_links_buf_crypt); if (knet_h->recv_from_links_buf_crypt) free(knet_h->recv_from_links_buf_crypt); free(knet_h->crypto_instance); knet_h->crypto_instance = NULL; } return; } diff --git a/libknet/nsscrypto.h b/libknet/nsscrypto.h index fa13fae5..2ae7216c 100644 --- a/libknet/nsscrypto.h +++ b/libknet/nsscrypto.h @@ -1,28 +1,28 @@ #ifndef NSSCRYPTO_H_DEFINED #define NSSCRYPTO_H_DEFINED #include #include "libknet.h" struct crypto_instance; int crypto_authenticate_and_decrypt ( struct crypto_instance *instance, unsigned char *buf, ssize_t *buf_len); int crypto_encrypt_and_sign ( struct crypto_instance *instance, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len); int crypto_init( knet_handle_t knet_h, - const struct knet_handle_cfg *knet_handle_cfg); + struct knet_handle_crypto_cfg *knet_handle_crypto_cfg); void crypto_fini( knet_handle_t knet_h); #endif /* NSSCRYPTO_H_DEFINED */ diff --git a/tests/khandle_test.c b/tests/khandle_test.c index 0c0a6209..a574ab26 100644 --- a/tests/khandle_test.c +++ b/tests/khandle_test.c @@ -1,63 +1,61 @@ #include "config.h" #include #include #include #include #include #include "libknet.h" #define HOST_LIST_SIZE 8192 #define HOST_LIST_LOOP 64 static int host_loop(knet_handle_t knet_h, struct knet_host *host, struct knet_host_search *search) { host->link_handler_policy = KNET_LINK_POLICY_ACTIVE; search->param1++; return KNET_HOST_FOREACH_NEXT; } int main(int argc, char *argv[]) { int sock, i, j; knet_handle_t knet_h; struct knet_host_search search; struct knet_handle_cfg knet_handle_cfg; sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { printf("Unable to create new socket\n"); exit(EXIT_FAILURE); } memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg)); knet_handle_cfg.fd = sock; knet_handle_cfg.node_id = 1; - knet_handle_cfg.crypto_cipher_type = (char *)"none"; - knet_handle_cfg.crypto_hash_type = (char *)"none"; knet_h = knet_handle_new(&knet_handle_cfg); for (i = 0; i < HOST_LIST_SIZE; i++) knet_host_add(knet_h, i); search.param1 = 0; for (i = 0; i < HOST_LIST_SIZE; i++) { for (j = 0; j < HOST_LIST_LOOP; j++) { knet_host_foreach(knet_h, host_loop, &search); } knet_host_remove(knet_h, i); } printf("Loop count: %u times\n", (unsigned int) search.param1); if (knet_handle_free(knet_h) != 0) { printf("Unable to free knet_handle\n"); exit(EXIT_FAILURE); } return 0; } diff --git a/tests/listener_test.c b/tests/listener_test.c index b88dc4dd..7abc576c 100644 --- a/tests/listener_test.c +++ b/tests/listener_test.c @@ -1,141 +1,139 @@ #include "config.h" #include #include #include #include #include #include "libknet-private.h" #define KNET_TEST_PORT 50000 static knet_handle_t knet_h; struct knet_listener *listener; static void test_add_listener(void) { struct sockaddr_in *address; listener = malloc(sizeof(struct knet_listener)); if (listener == NULL) { printf("Unable to create listener\n"); exit(EXIT_FAILURE); } memset(listener, 0, sizeof(struct knet_listener)); address = (struct sockaddr_in *) &listener->address; address->sin_family = AF_INET; address->sin_port = htons(KNET_TEST_PORT); address->sin_addr.s_addr = INADDR_ANY; if (knet_listener_add(knet_h, listener) != 0) { printf("Unable to add listener\n"); exit(EXIT_FAILURE); } } static void test_add_host(void) { struct knet_host *host; if (knet_host_add(knet_h, 1) != 0) { printf("Unable to add host to knet_handle\n"); exit(EXIT_FAILURE); } knet_host_get(knet_h, 1, &host); host->link[0].sock = listener->sock; host->link[0].configured = 1; knet_host_release(knet_h, &host); } int main(int argc, char *argv[]) { int err, sock; struct epoll_event ev; struct knet_handle_cfg knet_handle_cfg; sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { printf("Unable to create new socket\n"); exit(EXIT_FAILURE); } memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg)); knet_handle_cfg.fd = sock; knet_handle_cfg.node_id = 1; - knet_handle_cfg.crypto_cipher_type = (char *)"none"; - knet_handle_cfg.crypto_hash_type = (char *)"none"; if ((knet_h = knet_handle_new(&knet_handle_cfg)) == NULL) { printf("Unable to create new knet_handle_t\n"); exit(EXIT_FAILURE); } printf("Adding listener to handle\n"); test_add_listener(); memset(&ev, 0, sizeof(struct epoll_event)); /* don't try this at home :) */ err = epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_ADD, listener->sock, &ev); if (err != -1) { printf("Listener file descriptor not found in epollfd\n"); exit(EXIT_FAILURE); } printf("Listener file descriptor was added to epollfd\n"); printf("Adding host to handle\n"); test_add_host(); err = knet_listener_remove(knet_h, listener); if (err != -EBUSY) { printf("Listener socket should be in use\n"); exit(EXIT_FAILURE); } printf("Unable to remove listener with active links\n"); printf("Removing host from handle\n"); err = knet_host_remove(knet_h, 1); if (err != 0) { printf("Unable to remove host from knet_handle\n"); exit(EXIT_FAILURE); } printf("Removing listener\n"); err = knet_listener_remove(knet_h, listener); if (err != 0) { printf("Unable to remove listener from knet_handle\n"); exit(EXIT_FAILURE); } /* don't try this at home :) */ err = epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_DEL, listener->sock, &ev); if (err != -1) { printf("Listener file was present in epollfd\n"); exit(EXIT_FAILURE); } printf("Listener file descriptor was removed from epollfd\n"); if (knet_handle_free(knet_h) != 0) { printf("Unable to free knet_handle\n"); exit(EXIT_FAILURE); } return 0; } diff --git a/tests/ping_test.c b/tests/ping_test.c index a35cf30b..bb957cd3 100644 --- a/tests/ping_test.c +++ b/tests/ping_test.c @@ -1,257 +1,268 @@ #include "config.h" #include #include #include #include #include #include #include #include "libknet.h" -static unsigned char crypto_key[KNET_MAX_KEY_LEN]; static int knet_sock[2]; static knet_handle_t knet_h; static struct knet_handle_cfg knet_handle_cfg; +static struct knet_handle_crypto_cfg knet_handle_crypto_cfg; static in_port_t tok_inport(char *str) { int value = atoi(str); if ((value < 0) || (value > UINT16_MAX)) return 0; return (in_port_t) value; } static int tok_inaddrport(char *str, struct sockaddr_in *addr) { char *strhost, *strport, *tmp = NULL; strhost = strtok_r(str, ":", &tmp); strport = strtok_r(NULL, ":", &tmp); if (strport == NULL) addr->sin_port = htons(KNET_RING_DEFPORT); else addr->sin_port = htons(tok_inport(strport)); return inet_aton(strhost, &addr->sin_addr); } static void print_usage(char *name) { printf("usage: %s [:] [:port] [...]\n", name); printf("example: %s 0.0.0.0 192.168.0.2\n", name); printf("example: %s 127.0.0.1:50000 127.0.0.1:50000 crypto:aes256,sha1\n", name); } -static void set_crypto(int argc, char *argv[]) +static int set_crypto(int argc, char *argv[]) { int i, found = 0; for (i = 0; i < argc; i++) { if (!strncmp(argv[i], "crypto", 6)) { - printf("found crypto at: %i %s\n", i, argv[i]); found = 1; break; } } - if (!found) { - knet_handle_cfg.crypto_cipher_type = (char *)"none"; - knet_handle_cfg.crypto_hash_type = (char *)"none"; - } else { + + if (found) { char *tmp = NULL; strtok_r(argv[i], ":", &tmp); - knet_handle_cfg.crypto_cipher_type = strtok_r(NULL, ",", &tmp); - knet_handle_cfg.crypto_hash_type = strtok_r(NULL, ",", &tmp); + strncpy(knet_handle_crypto_cfg.crypto_model, + strtok_r(NULL, ",", &tmp), + sizeof(knet_handle_crypto_cfg.crypto_model) - 1); + strncpy(knet_handle_crypto_cfg.crypto_cipher_type, + strtok_r(NULL, ",", &tmp), + sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1); + strncpy(knet_handle_crypto_cfg.crypto_hash_type, + strtok_r(NULL, ",", &tmp), + sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1); + printf("Setting up encryption: model: %s crypto: %s hmac: %s\n", + knet_handle_crypto_cfg.crypto_model, + knet_handle_crypto_cfg.crypto_cipher_type, + knet_handle_crypto_cfg.crypto_hash_type); + return 1; } - printf("Setting up encryption: %s hmac: %s\n", - knet_handle_cfg.crypto_cipher_type, - knet_handle_cfg.crypto_hash_type); + + return 0; } static void argv_to_hosts(int argc, char *argv[]) { int err, i; struct sockaddr_in *address; struct knet_host *host; struct knet_listener *listener; listener = malloc(sizeof(struct knet_listener)); if (listener == NULL) { printf("Unable to create listener\n"); exit(EXIT_FAILURE); } memset(listener, 0, sizeof(struct knet_listener)); address = (struct sockaddr_in *) &listener->address; address->sin_family = AF_INET; err = tok_inaddrport(argv[1], address); if (err < 0) { printf("Unable to convert ip address: %s\n", argv[1]); exit(EXIT_FAILURE); } err = knet_listener_add(knet_h, listener); if (err != 0) { printf("Unable to start knet listener\n"); exit(EXIT_FAILURE); } for (i = 2; i < argc; i++) { if (!strncmp(argv[i], "crypto", 6)) continue; if (knet_host_add(knet_h, i - 1) != 0) { printf("Unable to add new knet_host\n"); exit(EXIT_FAILURE); } knet_host_get(knet_h, i - 1, &host); host->link[0].sock = listener->sock; host->link[0].address.ss_family = AF_INET; knet_link_timeout(&host->link[0], 1000, 5000, 2048); host->link[0].configured = 1; err = tok_inaddrport(argv[i], (struct sockaddr_in *) &host->link[0].address); if (err < 0) { printf("Unable to convert ip address: %s", argv[i]); exit(EXIT_FAILURE); } knet_host_release(knet_h, &host); } } /* Testing the latency/timeout: * # tc qdisc add dev lo root handle 1:0 netem delay 1s limit 1000 * # tc -d qdisc show dev lo * # tc qdisc del dev lo root */ static int print_link(knet_handle_t khandle, struct knet_host *host, struct knet_host_search *data) { int i; for (i = 0; i < KNET_MAX_LINK; i++) { if (host->link[i].configured != 1) continue; printf("host %p, link %p latency is %llu microsecs, status: %s\n", host, &host->link[i], host->link[i].latency, (host->link[i].connected == 0) ? "disconnected" : "connected"); } return KNET_HOST_FOREACH_NEXT; } static void sigint_handler(int signum) { int err; printf("Cleaning up...\n"); if (knet_h != NULL) { err = knet_handle_free(knet_h); if (err != 0) { printf("Unable to cleanup before exit\n"); exit(EXIT_FAILURE); } } exit(EXIT_SUCCESS); } int main(int argc, char *argv[]) { char buff[1024]; size_t len; fd_set rfds; struct timeval tv; struct knet_host_search print_search; if (argc < 3) { print_usage(argv[0]); exit(EXIT_FAILURE); } if (socketpair(AF_UNIX, SOCK_STREAM, IPPROTO_IP, knet_sock) != 0) { printf("Unable to create socket\n"); exit(EXIT_FAILURE); } knet_h = NULL; if (signal(SIGINT, sigint_handler) == SIG_ERR) { printf("Unable to configure SIGINT handler\n"); exit(EXIT_FAILURE); } memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg)); knet_handle_cfg.fd = knet_sock[0]; knet_handle_cfg.node_id = 1; - set_crypto(argc, argv); - knet_handle_cfg.private_key = crypto_key; - knet_handle_cfg.private_key_len = sizeof(crypto_key); - - /* - * fake a 4KB key of all 0's - */ - memset(knet_handle_cfg.private_key, 0, sizeof(crypto_key)); if ((knet_h = knet_handle_new(&knet_handle_cfg)) == NULL) { printf("Unable to create new knet_handle_t\n"); exit(EXIT_FAILURE); } + if (set_crypto(argc, argv)) { + memset(knet_handle_crypto_cfg.private_key, 0, KNET_MAX_KEY_LEN); + knet_handle_crypto_cfg.private_key_len = KNET_MAX_KEY_LEN; + if (knet_handle_crypto(knet_h, &knet_handle_crypto_cfg)) { + printf("Unable to init crypto\n"); + exit(EXIT_FAILURE); + } + } else { + printf("Crypto not activated\n"); + } + argv_to_hosts(argc, argv); knet_handle_setfwd(knet_h, 1); while (1) { ssize_t wlen; knet_host_foreach(knet_h, print_link, &print_search); printf("Sending 'Hello World!' frame\n"); wlen = write(knet_sock[1], "Hello World!", 13); if (wlen != 13) printf("Unable to send Hello World! to socket!\n"); tv.tv_sec = 5; tv.tv_usec = 0; select_loop: FD_ZERO(&rfds); FD_SET(knet_sock[1], &rfds); len = select(FD_SETSIZE, &rfds, NULL, NULL, &tv); /* uncomment this to replicate the one-message problem */ /* usleep(500000); */ if (len < 0) { printf("Unable select over knet_handle_t\n"); exit(EXIT_FAILURE); } else if (FD_ISSET(knet_sock[1], &rfds)) { len = read(knet_sock[1], buff, sizeof(buff)); printf("Received data (%zu bytes): '%s'\n", len, buff); } if ((tv.tv_sec > 0) || (tv.tv_usec > 0)) goto select_loop; } /* FIXME: allocated hosts should be free'd */ return 0; }