FD.io VPP  v21.06-1-gbb7418cf9
Vector Packet Processing
wireguard_cli.c
Go to the documentation of this file.
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>
20 #include <wireguard/wireguard_if.h>
21 
22 static clib_error_t *
24  unformat_input_t * input, vlib_cli_command_t * cmd)
25 {
26  wg_main_t *wmp = &wg_main;
27  unformat_input_t _line_input, *line_input = &_line_input;
32  u8 *private_key_64;
33  u32 port, generate_key = 0;
34  int rv;
35 
36  error = NULL;
37  instance = sw_if_index = ~0;
38  private_key_64 = 0;
39  port = 0;
40 
41  wg_feature_init (wmp);
42 
43  if (unformat_user (input, unformat_line_input, line_input))
44  {
45  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
46  {
47  if (unformat (line_input, "instance %d", &instance))
48  ;
49  else if (unformat (line_input, "private-key %s", &private_key_64))
50  {
51  if (!(key_from_base64 (private_key_64,
52  NOISE_KEY_LEN_BASE64, private_key)))
53  {
54  error = clib_error_return (0, "Error parsing private key");
55  break;
56  }
57  }
58  else if (unformat (line_input, "listen-port %d", &port))
59  ;
60  else if (unformat (line_input, "port %d", &port))
61  ;
62  else if (unformat (line_input, "generate-key"))
63  generate_key = 1;
64  else
65  if (unformat (line_input, "src %U", unformat_ip_address, &src_ip))
66  ;
67  else
68  {
69  error = clib_error_return (0, "unknown input: %U",
70  format_unformat_error, line_input);
71  break;
72  }
73  }
74 
75  unformat_free (line_input);
76 
77  if (error)
78  return error;
79  }
80 
81  if (generate_key)
82  curve25519_gen_secret (private_key);
83 
84  rv = wg_if_create (instance, private_key, port, &src_ip, &sw_if_index);
85 
86  if (rv)
87  return clib_error_return (0, "wireguard interface create failed");
88 
90  sw_if_index);
91  return 0;
92 }
93 
94 /*?
95  * Create a Wireguard interface.
96 ?*/
97 /* *INDENT-OFF* */
98 VLIB_CLI_COMMAND (wg_if_create_command, static) = {
99  .path = "wireguard create",
100  .short_help = "wireguard create listen-port <port> "
101  "private-key <key> src <IP> [generate-key]",
102  .function = wg_if_create_cli,
103 };
104 /* *INDENT-ON* */
105 
106 static clib_error_t *
108  unformat_input_t * input, vlib_cli_command_t * cmd)
109 {
110  wg_main_t *wmp = &wg_main;
111  vnet_main_t *vnm;
113  int rv;
114 
115  wg_feature_init (wmp);
116 
117  vnm = vnet_get_main ();
118  sw_if_index = ~0;
119 
121  {
122  if (unformat
123  (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
124  ;
125  else
126  break;
127  }
128 
129  if (~0 != sw_if_index)
130  {
131  rv = wg_if_delete (sw_if_index);
132 
133  if (rv)
134  return clib_error_return (0, "wireguard interface delete failed");
135  }
136  else
137  return clib_error_return (0, "no such interface: %U",
138  format_unformat_error, input);
139 
140  return 0;
141 }
142 
143 /*?
144  * Delete a Wireguard interface.
145 ?*/
146 /* *INDENT-OFF* */
147 VLIB_CLI_COMMAND (wg_if_delete_command, static) = {
148  .path = "wireguard delete",
149  .short_help = "wireguard delete <interface>",
150  .function = wg_if_delete_cli,
151 };
152 /* *INDENT-ON* */
153 
154 
155 static clib_error_t *
157  unformat_input_t * input, vlib_cli_command_t * cmd)
158 {
159  vnet_main_t *vnm = vnet_get_main ();
160  wg_main_t *wmp = &wg_main;
161  clib_error_t *error = NULL;
162  unformat_input_t _line_input, *line_input = &_line_input;
163 
164  u8 *public_key_64 = 0;
166  fib_prefix_t allowed_ip, *allowed_ips = NULL;
167  ip_prefix_t pfx;
169  u32 portDst = 0, table_id = 0;
171  u32 tun_sw_if_index = ~0;
172  u32 peer_index;
173  int rv;
174 
175  if (!unformat_user (input, unformat_line_input, line_input))
176  return 0;
177 
178  wg_feature_init (wmp);
179 
180  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
181  {
182  if (unformat (line_input, "public-key %s", &public_key_64))
183  {
184  if (!(key_from_base64 (public_key_64,
185  NOISE_KEY_LEN_BASE64, public_key)))
186  {
187  error = clib_error_return (0, "Error parsing private key");
188  goto done;
189  }
190  }
191  else if (unformat (line_input, "endpoint %U", unformat_ip_address, &ip))
192  ;
193  else if (unformat (line_input, "table-id %d", &table_id))
194  ;
195  else if (unformat (line_input, "port %d", &portDst))
196  ;
197  else if (unformat (line_input, "persistent-keepalive %d",
198  &persistent_keepalive))
199  ;
200  else if (unformat (line_input, "allowed-ip %U",
201  unformat_ip_prefix, &pfx))
202  {
203  ip_prefix_to_fib_prefix (&pfx, &allowed_ip);
204  vec_add1 (allowed_ips, allowed_ip);
205  }
206  else if (unformat (line_input, "%U",
207  unformat_vnet_sw_interface, vnm, &tun_sw_if_index))
208  ;
209  else
210  {
211  error = clib_error_return (0, "Input error");
212  goto done;
213  }
214  }
215 
216  if (AF_IP6 == ip_addr_version (&ip) ||
217  FIB_PROTOCOL_IP6 == allowed_ip.fp_proto)
218  rv = VNET_API_ERROR_INVALID_PROTOCOL;
219  else
220  rv = wg_peer_add (tun_sw_if_index,
221  public_key,
222  table_id,
223  &ip_addr_46 (&ip),
224  allowed_ips,
225  portDst, persistent_keepalive, &peer_index);
226 
227  switch (rv)
228  {
229  case VNET_API_ERROR_KEY_LENGTH:
230  error = clib_error_return (0, "Error parsing public key");
231  break;
232  case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
233  error = clib_error_return (0, "Peer already exist");
234  break;
235  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
236  error = clib_error_return (0, "Tunnel is not specified");
237  break;
238  case VNET_API_ERROR_LIMIT_EXCEEDED:
239  error = clib_error_return (0, "Max peers limit");
240  break;
241  case VNET_API_ERROR_INIT_FAILED:
242  error = clib_error_return (0, "wireguard device parameters is not set");
243  break;
244  case VNET_API_ERROR_INVALID_PROTOCOL:
245  error = clib_error_return (0, "ipv6 not supported yet");
246  break;
247  }
248 
249 done:
250  vec_free (public_key_64);
251  vec_free (allowed_ips);
252  unformat_free (line_input);
253  return error;
254 }
255 
256 /* *INDENT-OFF* */
257 VLIB_CLI_COMMAND (wg_peer_add_command, static) =
258 {
259  .path = "wireguard peer add",
260  .short_help = "wireguard peer add <wg_int> public-key <pub_key_other>"
261  "endpoint <ip4_dst> allowed-ip <prefix>"
262  "dst-port [port_dst] persistent-keepalive [keepalive_interval]",
263  .function = wg_peer_add_command_fn,
264 };
265 /* *INDENT-ON* */
266 
267 static clib_error_t *
269  unformat_input_t * input, vlib_cli_command_t * cmd)
270 {
271  wg_main_t *wmp = &wg_main;
272  clib_error_t *error = NULL;
273  u32 peer_index;
274  int rv;
275 
276  unformat_input_t _line_input, *line_input = &_line_input;
277  if (!unformat_user (input, unformat_line_input, line_input))
278  return 0;
279 
280  wg_feature_init (wmp);
281 
282  if (unformat (line_input, "%d", &peer_index))
283  ;
284  else
285  {
286  error = clib_error_return (0, "Input error");
287  goto done;
288  }
289 
290  rv = wg_peer_remove (peer_index);
291 
292  switch (rv)
293  {
294  case VNET_API_ERROR_KEY_LENGTH:
295  error = clib_error_return (0, "Error parsing public key");
296  break;
297  }
298 
299 done:
300  unformat_free (line_input);
301  return error;
302 }
303 
304 /* *INDENT-OFF* */
305 VLIB_CLI_COMMAND (wg_peer_remove_command, static) =
306 {
307  .path = "wireguard peer remove",
308  .short_help = "wireguard peer remove <index>",
309  .function = wg_peer_remove_command_fn,
310 };
311 /* *INDENT-ON* */
312 
313 static walk_rc_t
314 wg_peer_show_one (index_t peeri, void *arg)
315 {
316  vlib_cli_output (arg, "%U", format_wg_peer, peeri);
317 
318  return (WALK_CONTINUE);
319 }
320 
321 static clib_error_t *
323  unformat_input_t * input, vlib_cli_command_t * cmd)
324 {
326 
327  return NULL;
328 }
329 
330 /* *INDENT-OFF* */
331 VLIB_CLI_COMMAND (wg_show_peers_command, static) =
332 {
333  .path = "show wireguard peer",
334  .short_help = "show wireguard peer",
335  .function = wg_show_peer_command_fn,
336 };
337 /* *INDENT-ON* */
338 
339 static walk_rc_t
340 wg_if_show_one (index_t itfi, void *arg)
341 {
342  vlib_cli_output (arg, "%U", format_wg_if, itfi);
343 
344  return (WALK_CONTINUE);
345 }
346 
347 static clib_error_t *
349  unformat_input_t * input, vlib_cli_command_t * cmd)
350 {
351  wg_main_t *wmp = &wg_main;
352 
353  wg_feature_init (wmp);
354 
356 
357  return NULL;
358 }
359 
360 /* *INDENT-OFF* */
361 VLIB_CLI_COMMAND (wg_show_itfs_command, static) =
362 {
363  .path = "show wireguard interface",
364  .short_help = "show wireguard",
365  .function = wg_show_if_command_fn,
366 };
367 /* *INDENT-ON* */
368 
369 /*
370  * fd.io coding-style-patch-verification: ON
371  *
372  * Local Variables:
373  * eval: (c-set-style "gnu")
374  * End:
375  */
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:211
#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:410
#define ip_addr_46(_a)
Definition: ip_types.h:90
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:43
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:607
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
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:93
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
unsigned int u32
Definition: types.h:88
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:23
vl_api_prefix_t allowed_ips[n_allowed_ips]
Definition: wireguard.api:107
void wg_feature_init(wg_main_t *wmp)
Aggregate type for a prefix.
Definition: fib_types.h:202
#define clib_error_return(e, args...)
Definition: error.h:99
vnet_main_t * vnet_get_main(void)
int wg_if_delete(u32 sw_if_index)
Definition: wireguard_if.c:322
static clib_error_t * wg_peer_add_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
int __clib_unused rv
Definition: application.c:491
#define NOISE_PUBLIC_KEY_LEN
unformat_function_t unformat_line_input
Definition: format.h:275
Definition: cJSON.c:88
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
u8 * format_wg_if(u8 *s, va_list *args)
Definition: wireguard_if.c:45
u8 private_key[32]
Definition: wireguard.api:35
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
vlib_main_t * vm
X-connect all packets from the HOST to the PHY.
Definition: nat44_ei.c:3047
bool key_from_base64(const u8 *src, size_t src_len, u8 *out)
u8 public_key[32]
Definition: wireguard.api:36
#define UNFORMAT_END_OF_INPUT
Definition: format.h:137
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:163
wg_main_t wg_main
Definition: wireguard.c:26
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:716
u16 persistent_keepalive
Definition: wireguard.api:101
bool curve25519_gen_secret(u8 secret_key[CURVE25519_KEY_SIZE])
Definition: wireguard_key.c:84
void wg_if_walk(wg_if_walk_cb_t fn, void *data)
Definition: wireguard_if.c:371
vl_api_address_t ip
Definition: l2.api:558
u32 instance
Definition: gre.api:51
static void unformat_free(unformat_input_t *i)
Definition: format.h:155
vl_api_address_t src_ip
Definition: wireguard.api:38
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:102
u16 port
Definition: lb_types.api:73
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:239
uword unformat_ip_prefix(unformat_input_t *input, va_list *args)
Definition: ip_types.c:64
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:163