@@ -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+
647819SHELL_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