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