wireguard: fix license headers
[vpp.git] / src / plugins / wireguard / wireguard_cli.c
1 /*
2  * Copyright (c) 2020 Cisco and/or its affiliates.
3  * Copyright (c) 2020 Doc.ai and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <wireguard/wireguard.h>
18 #include <wireguard/wireguard_key.h>
19 #include <wireguard/wireguard_peer.h>
20 #include <wireguard/wireguard_if.h>
21
22 static clib_error_t *
23 wg_if_create_cli (vlib_main_t * vm,
24                   unformat_input_t * input, vlib_cli_command_t * cmd)
25 {
26   unformat_input_t _line_input, *line_input = &_line_input;
27   u8 private_key[NOISE_PUBLIC_KEY_LEN];
28   u32 instance, sw_if_index;
29   ip_address_t src_ip;
30   clib_error_t *error;
31   u8 *private_key_64;
32   u32 port, generate_key = 0;
33   int rv;
34
35   error = NULL;
36   instance = sw_if_index = ~0;
37   private_key_64 = 0;
38   port = 0;
39
40   if (unformat_user (input, unformat_line_input, line_input))
41     {
42       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
43         {
44           if (unformat (line_input, "instance %d", &instance))
45             ;
46           else if (unformat (line_input, "private-key %s", &private_key_64))
47             {
48               if (!(key_from_base64 (private_key_64,
49                                      NOISE_KEY_LEN_BASE64, private_key)))
50                 {
51                   error = clib_error_return (0, "Error parsing private key");
52                   break;
53                 }
54             }
55           else if (unformat (line_input, "listen-port %d", &port))
56             ;
57           else if (unformat (line_input, "port %d", &port))
58             ;
59           else if (unformat (line_input, "generate-key"))
60             generate_key = 1;
61           else
62             if (unformat (line_input, "src %U", unformat_ip_address, &src_ip))
63             ;
64           else
65             {
66               error = clib_error_return (0, "unknown input: %U",
67                                          format_unformat_error, line_input);
68               break;
69             }
70         }
71
72       unformat_free (line_input);
73
74       if (error)
75         return error;
76     }
77
78   if (generate_key)
79     curve25519_gen_secret (private_key);
80
81   rv = wg_if_create (instance, private_key, port, &src_ip, &sw_if_index);
82
83   if (rv)
84     return clib_error_return (0, "wireguard interface create failed");
85
86   vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
87                    sw_if_index);
88   return 0;
89 }
90
91 /*?
92  * Create a Wireguard interface.
93 ?*/
94 /* *INDENT-OFF* */
95 VLIB_CLI_COMMAND (wg_if_create_command, static) = {
96   .path = "wireguard create",
97   .short_help = "wireguard create listen-port <port> "
98     "private-key <key> src <IP> [generate-key]",
99   .function = wg_if_create_cli,
100 };
101 /* *INDENT-ON* */
102
103 static clib_error_t *
104 wg_if_delete_cli (vlib_main_t * vm,
105                   unformat_input_t * input, vlib_cli_command_t * cmd)
106 {
107   vnet_main_t *vnm;
108   u32 sw_if_index;
109   int rv;
110
111   vnm = vnet_get_main ();
112   sw_if_index = ~0;
113
114   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
115     {
116       if (unformat
117           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
118         ;
119       else
120         break;
121     }
122
123   if (~0 != sw_if_index)
124     {
125       rv = wg_if_delete (sw_if_index);
126
127       if (rv)
128         return clib_error_return (0, "wireguard interface delete failed");
129     }
130   else
131     return clib_error_return (0, "no such interface: %U",
132                               format_unformat_error, input);
133
134   return 0;
135 }
136
137 /*?
138  * Delete a Wireguard interface.
139 ?*/
140 /* *INDENT-OFF* */
141 VLIB_CLI_COMMAND (wg_if_delete_command, static) = {
142   .path = "wireguard delete",
143   .short_help = "wireguard delete <interface>",
144   .function = wg_if_delete_cli,
145 };
146 /* *INDENT-ON* */
147
148
149 static clib_error_t *
150 wg_peer_add_command_fn (vlib_main_t * vm,
151                         unformat_input_t * input, vlib_cli_command_t * cmd)
152 {
153   vnet_main_t *vnm = vnet_get_main ();
154   clib_error_t *error = NULL;
155   unformat_input_t _line_input, *line_input = &_line_input;
156
157   u8 *public_key_64 = 0;
158   u8 public_key[NOISE_PUBLIC_KEY_LEN];
159   fib_prefix_t allowed_ip, *allowed_ips = NULL;
160   ip_prefix_t pfx;
161   ip_address_t ip;
162   u32 portDst = 0, table_id = 0;
163   u32 persistent_keepalive = 0;
164   u32 tun_sw_if_index = ~0;
165   u32 peer_index;
166   int rv;
167
168   if (!unformat_user (input, unformat_line_input, line_input))
169     return 0;
170
171   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
172     {
173       if (unformat (line_input, "public-key %s", &public_key_64))
174         {
175           if (!(key_from_base64 (public_key_64,
176                                  NOISE_KEY_LEN_BASE64, public_key)))
177             {
178               error = clib_error_return (0, "Error parsing private key");
179               goto done;
180             }
181         }
182       else if (unformat (line_input, "endpoint %U", unformat_ip_address, &ip))
183         ;
184       else if (unformat (line_input, "table-id %d", &table_id))
185         ;
186       else if (unformat (line_input, "port %d", &portDst))
187         ;
188       else if (unformat (line_input, "persistent-keepalive %d",
189                          &persistent_keepalive))
190         ;
191       else if (unformat (line_input, "allowed-ip %U",
192                          unformat_ip_prefix, &pfx))
193         {
194           ip_prefix_to_fib_prefix (&pfx, &allowed_ip);
195           vec_add1 (allowed_ips, allowed_ip);
196         }
197       else if (unformat (line_input, "%U",
198                          unformat_vnet_sw_interface, vnm, &tun_sw_if_index))
199         ;
200       else
201         {
202           error = clib_error_return (0, "Input error");
203           goto done;
204         }
205     }
206
207   if (AF_IP6 == ip_addr_version (&ip) ||
208       FIB_PROTOCOL_IP6 == allowed_ip.fp_proto)
209     rv = VNET_API_ERROR_INVALID_PROTOCOL;
210   else
211     rv = wg_peer_add (tun_sw_if_index,
212                       public_key,
213                       table_id,
214                       &ip_addr_46 (&ip),
215                       allowed_ips,
216                       portDst, persistent_keepalive, &peer_index);
217
218   switch (rv)
219     {
220     case VNET_API_ERROR_KEY_LENGTH:
221       error = clib_error_return (0, "Error parsing public key");
222       break;
223     case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
224       error = clib_error_return (0, "Peer already exist");
225       break;
226     case VNET_API_ERROR_INVALID_SW_IF_INDEX:
227       error = clib_error_return (0, "Tunnel is not specified");
228       break;
229     case VNET_API_ERROR_LIMIT_EXCEEDED:
230       error = clib_error_return (0, "Max peers limit");
231       break;
232     case VNET_API_ERROR_INIT_FAILED:
233       error = clib_error_return (0, "wireguard device parameters is not set");
234       break;
235     case VNET_API_ERROR_INVALID_PROTOCOL:
236       error = clib_error_return (0, "ipv6 not supported yet");
237       break;
238     }
239
240 done:
241   vec_free (public_key_64);
242   vec_free (allowed_ips);
243   unformat_free (line_input);
244   return error;
245 }
246
247 /* *INDENT-OFF* */
248 VLIB_CLI_COMMAND (wg_peer_add_command, static) =
249 {
250   .path = "wireguard peer add",
251   .short_help = "wireguard peer add <wg_int> public-key <pub_key_other>"
252   "endpoint <ip4_dst> allowed-ip <prefix>"
253   "dst-port [port_dst] persistent-keepalive [keepalive_interval]",
254   .function = wg_peer_add_command_fn,
255 };
256 /* *INDENT-ON* */
257
258 static clib_error_t *
259 wg_peer_remove_command_fn (vlib_main_t * vm,
260                            unformat_input_t * input, vlib_cli_command_t * cmd)
261 {
262   clib_error_t *error = NULL;
263   u32 peer_index;
264   int rv;
265
266   unformat_input_t _line_input, *line_input = &_line_input;
267   if (!unformat_user (input, unformat_line_input, line_input))
268     return 0;
269
270   if (unformat (line_input, "%d", &peer_index))
271     ;
272   else
273     {
274       error = clib_error_return (0, "Input error");
275       goto done;
276     }
277
278   rv = wg_peer_remove (peer_index);
279
280   switch (rv)
281     {
282     case VNET_API_ERROR_KEY_LENGTH:
283       error = clib_error_return (0, "Error parsing public key");
284       break;
285     }
286
287 done:
288   unformat_free (line_input);
289   return error;
290 }
291
292 /* *INDENT-OFF* */
293 VLIB_CLI_COMMAND (wg_peer_remove_command, static) =
294 {
295   .path = "wireguard peer remove",
296   .short_help = "wireguard peer remove <index>",
297   .function = wg_peer_remove_command_fn,
298 };
299 /* *INDENT-ON* */
300
301 static walk_rc_t
302 wg_peer_show_one (index_t peeri, void *arg)
303 {
304   vlib_cli_output (arg, "%U", format_wg_peer, peeri);
305
306   return (WALK_CONTINUE);
307 }
308
309 static clib_error_t *
310 wg_show_peer_command_fn (vlib_main_t * vm,
311                          unformat_input_t * input, vlib_cli_command_t * cmd)
312 {
313   wg_peer_walk (wg_peer_show_one, vm);
314
315   return NULL;
316 }
317
318 /* *INDENT-OFF* */
319 VLIB_CLI_COMMAND (wg_show_peers_command, static) =
320 {
321   .path = "show wireguard peer",
322   .short_help = "show wireguard peer",
323   .function = wg_show_peer_command_fn,
324 };
325 /* *INDENT-ON* */
326
327 static walk_rc_t
328 wg_if_show_one (index_t itfi, void *arg)
329 {
330   vlib_cli_output (arg, "%U", format_wg_if, itfi);
331
332   return (WALK_CONTINUE);
333 }
334
335 static clib_error_t *
336 wg_show_if_command_fn (vlib_main_t * vm,
337                        unformat_input_t * input, vlib_cli_command_t * cmd)
338 {
339   wg_if_walk (wg_if_show_one, vm);
340
341   return NULL;
342 }
343
344 /* *INDENT-OFF* */
345 VLIB_CLI_COMMAND (wg_show_itfs_command, static) =
346 {
347   .path = "show wireguard interface",
348   .short_help = "show wireguard",
349   .function = wg_show_if_command_fn,
350 };
351 /* *INDENT-ON* */
352
353 /*
354  * fd.io coding-style-patch-verification: ON
355  *
356  * Local Variables:
357  * eval: (c-set-style "gnu")
358  * End:
359  */