Skip to content

Commit 8840200

Browse files
committed
net: shell: wg: Add setup command
Add a way to add private key, peer endpoint and keepalive when setting up the wireguard connection using the shell. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
1 parent 5ac7441 commit 8840200

File tree

1 file changed

+177
-0
lines changed

1 file changed

+177
-0
lines changed

‎subsys/net/lib/shell/wg_shell.c‎

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ LOG_MODULE_DECLARE(net_shell);
1212

1313
#include <zephyr/sys/sys_getopt.h>
1414
#include <zephyr/net/virtual.h>
15+
#include <zephyr/net/virtual_mgmt.h>
1516
#include <zephyr/net/wireguard.h>
1617

1718
#include "net_shell_private.h"
@@ -644,6 +645,177 @@ static int cmd_wg_stats(const struct shell *sh, size_t argc, char *argv[])
644645
return 0;
645646
}
646647

648+
#if defined(CONFIG_WIREGUARD_SHELL)
649+
static int parse_setup_args_to_params(const struct shell *sh,
650+
int argc, char *argv[],
651+
char *private_key,
652+
size_t private_key_len,
653+
struct net_if **vpn_iface)
654+
{
655+
struct sys_getopt_state *state;
656+
struct net_if *iface;
657+
int option_index = 1;
658+
int iface_idx;
659+
int opt;
660+
int ret;
661+
662+
static const struct sys_getopt_option long_options[] = {
663+
{ "private-key", sys_getopt_required_argument, 0, 'k' },
664+
{ "iface", sys_getopt_required_argument, 0, 'i' },
665+
{ "help", sys_getopt_no_argument, 0, 'h' },
666+
{ 0, 0, 0, 0 }
667+
};
668+
669+
while ((opt = sys_getopt_long(argc, argv, "k:i:h",
670+
long_options, &option_index)) != -1) {
671+
state = sys_getopt_state_get();
672+
673+
switch (opt) {
674+
case 'k':
675+
strncpy(private_key, state->optarg, private_key_len);
676+
break;
677+
case 'i':
678+
ret = 0;
679+
iface_idx = shell_strtol(state->optarg, 10, &ret);
680+
if (ret < 0 || iface_idx == 0) {
681+
PR_ERROR("Invalid interface index \"%s\"\n",
682+
state->optarg);
683+
return ret;
684+
}
685+
686+
iface = net_if_get_by_index(iface_idx);
687+
if (iface == NULL) {
688+
PR_ERROR("Invalid interface: %d\n", iface_idx);
689+
return -EINVAL;
690+
}
691+
692+
if (!(net_virtual_get_iface_capabilities(iface) & VIRTUAL_INTERFACE_VPN)) {
693+
PR_ERROR("Interface %d is not a VPN one\n", iface_idx);
694+
return -ENOENT;
695+
}
696+
697+
*vpn_iface = iface;
698+
break;
699+
case 'h':
700+
case '?':
701+
shell_help(sh);
702+
return SHELL_CMD_HELP_PRINTED;
703+
default:
704+
PR_ERROR("Invalid option %c\n", state->optopt);
705+
shell_help(sh);
706+
return SHELL_CMD_HELP_PRINTED;
707+
}
708+
}
709+
710+
return 0;
711+
}
712+
713+
/* User data for the interface callback */
714+
struct ud {
715+
struct net_if *vpn[CONFIG_WIREGUARD_MAX_PEER];
716+
};
717+
718+
static void wg_iface_cb(struct net_if *iface, void *user_data)
719+
{
720+
struct ud *ud = user_data;
721+
722+
if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
723+
return;
724+
}
725+
726+
if (!(net_virtual_get_iface_capabilities(iface) & VIRTUAL_INTERFACE_VPN)) {
727+
return;
728+
}
729+
730+
for (int i = 0; i < CONFIG_WIREGUARD_MAX_PEER; i++) {
731+
if (ud->vpn[i] != NULL) {
732+
continue;
733+
}
734+
735+
ud->vpn[i] = iface;
736+
return;
737+
}
738+
}
739+
740+
static void crypto_zero(void *dest, size_t len)
741+
{
742+
volatile uint8_t *p = (uint8_t *)dest;
743+
744+
while (len--) {
745+
*p++ = 0;
746+
}
747+
}
748+
#endif
749+
750+
static int cmd_wg_setup(const struct shell *sh, size_t argc, char *argv[])
751+
{
752+
#if defined(CONFIG_WIREGUARD_SHELL)
753+
struct virtual_interface_req_params params = { 0 };
754+
uint8_t my_private_key[WG_PRIVATE_KEY_LEN] = { 0 };
755+
char private_key[WG_PRIVATE_KEY_LEN * 2] = { 0 };
756+
struct net_if *iface = NULL;
757+
struct ud user_data = { 0 };
758+
size_t olen = 0;
759+
int ret;
760+
761+
if (argc < 2) {
762+
PR_ERROR("Invalid number of arguments\n");
763+
return -EINVAL;
764+
}
765+
766+
if (parse_setup_args_to_params(sh, argc, argv,
767+
private_key, sizeof(private_key),
768+
&iface) != 0) {
769+
return -ENOEXEC;
770+
}
771+
772+
/* public_key contains the private key in base64 format at this point */
773+
ret = base64_decode(my_private_key, sizeof(my_private_key),
774+
&olen, private_key, strlen(private_key));
775+
if (ret < 0 || olen != sizeof(my_private_key)) {
776+
PR_ERROR("Invalid private key (len %d)\n", olen);
777+
return -EINVAL;
778+
}
779+
780+
params.private_key.data = my_private_key;
781+
params.private_key.len = sizeof(my_private_key);
782+
783+
if (iface == NULL) {
784+
net_if_foreach(wg_iface_cb, &user_data);
785+
786+
if (user_data.vpn[0] == NULL) {
787+
PR_ERROR("No available VPN interface for the new peer\n");
788+
return -ENODEV;
789+
}
790+
791+
iface = user_data.vpn[0];
792+
if (iface == NULL) {
793+
PR_ERROR("No available VPN interface for the new peer\n");
794+
return -ENODEV;
795+
}
796+
}
797+
798+
ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PRIVATE_KEY,
799+
iface, &params, sizeof(params));
800+
801+
crypto_zero(private_key, sizeof(private_key));
802+
803+
if (ret < 0) {
804+
LOG_ERR("Cannot set private key (%d)", ret);
805+
return ret;
806+
}
807+
808+
PR_INFO("VPN interface %d is set up with the provided private key. "
809+
"You can add peers using the 'net wg add' command.\n",
810+
net_if_get_by_iface(iface));
811+
#else
812+
PR_INFO("Set %s to enable %s support.\n", "CONFIG_WIREGUARD",
813+
"Wireguard VPN");
814+
#endif /* CONFIG_WIREGUARD_SHELL */
815+
816+
return 0;
817+
}
818+
647819
SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_wg,
648820
SHELL_CMD_ARG(add, NULL,
649821
SHELL_HELP("Add a peer in order to establish a VPN connection",
@@ -679,6 +851,11 @@ SHELL_STATIC_SUBCMD_SET_CREATE(net_cmd_wg,
679851
"To get detailed information about a specific connection, "
680852
"use the 'show <id>' command", "[<id>]"),
681853
cmd_net_wg, 1, 1),
854+
SHELL_CMD_ARG(setup, NULL,
855+
SHELL_HELP("Setup local VPN network interface",
856+
"[-i, --iface=<interface index>]: Interface index\n"
857+
"-k, --private-key <key>: Private key in base64 format"),
858+
cmd_wg_setup, 1, 7),
682859
SHELL_CMD_ARG(stats, NULL,
683860
SHELL_HELP("Show statistics information about the Wireguard VPN connections."
684861
" The statistics can be reset by using the 'reset' command",

0 commit comments

Comments
 (0)