Line data Source code
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 0 : wg_if_create_cli (vlib_main_t * vm,
24 : unformat_input_t * input, vlib_cli_command_t * cmd)
25 : {
26 0 : wg_main_t *wmp = &wg_main;
27 0 : unformat_input_t _line_input, *line_input = &_line_input;
28 : u8 private_key[NOISE_PUBLIC_KEY_LEN + 1];
29 : u32 instance, sw_if_index;
30 : ip_address_t src_ip;
31 : clib_error_t *error;
32 : u8 *private_key_64;
33 0 : u32 port, generate_key = 0;
34 : int rv;
35 :
36 0 : error = NULL;
37 0 : instance = sw_if_index = ~0;
38 0 : private_key_64 = 0;
39 0 : port = 0;
40 :
41 0 : wg_feature_init (wmp);
42 :
43 0 : if (unformat_user (input, unformat_line_input, line_input))
44 : {
45 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
46 : {
47 0 : if (unformat (line_input, "instance %d", &instance))
48 : ;
49 0 : else if (unformat (line_input, "private-key %s", &private_key_64))
50 : {
51 0 : if (!(key_from_base64 (private_key_64,
52 : NOISE_KEY_LEN_BASE64, private_key)))
53 : {
54 0 : error = clib_error_return (0, "Error parsing private key");
55 0 : break;
56 : }
57 : }
58 0 : else if (unformat (line_input, "listen-port %d", &port))
59 : ;
60 0 : else if (unformat (line_input, "port %d", &port))
61 : ;
62 0 : else if (unformat (line_input, "generate-key"))
63 0 : generate_key = 1;
64 : else
65 0 : if (unformat (line_input, "src %U", unformat_ip_address, &src_ip))
66 : ;
67 : else
68 : {
69 0 : error = clib_error_return (0, "unknown input: %U",
70 : format_unformat_error, line_input);
71 0 : break;
72 : }
73 : }
74 :
75 0 : unformat_free (line_input);
76 :
77 0 : if (error)
78 0 : return error;
79 : }
80 :
81 0 : if (generate_key)
82 0 : curve25519_gen_secret (private_key);
83 :
84 0 : rv = wg_if_create (instance, private_key, port, &src_ip, &sw_if_index);
85 :
86 0 : if (rv)
87 0 : return clib_error_return (0, "wireguard interface create failed");
88 :
89 0 : vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
90 : sw_if_index);
91 0 : return 0;
92 : }
93 :
94 : /*?
95 : * Create a Wireguard interface.
96 : ?*/
97 : /* *INDENT-OFF* */
98 1151 : 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 *
107 0 : wg_if_delete_cli (vlib_main_t * vm,
108 : unformat_input_t * input, vlib_cli_command_t * cmd)
109 : {
110 0 : wg_main_t *wmp = &wg_main;
111 : vnet_main_t *vnm;
112 : u32 sw_if_index;
113 : int rv;
114 :
115 0 : wg_feature_init (wmp);
116 :
117 0 : vnm = vnet_get_main ();
118 0 : sw_if_index = ~0;
119 :
120 0 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
121 : {
122 0 : if (unformat
123 : (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
124 : ;
125 : else
126 0 : break;
127 : }
128 :
129 0 : if (~0 != sw_if_index)
130 : {
131 0 : rv = wg_if_delete (sw_if_index);
132 :
133 0 : if (rv)
134 0 : return clib_error_return (0, "wireguard interface delete failed");
135 : }
136 : else
137 0 : return clib_error_return (0, "no such interface: %U",
138 : format_unformat_error, input);
139 :
140 0 : return 0;
141 : }
142 :
143 : /*?
144 : * Delete a Wireguard interface.
145 : ?*/
146 : /* *INDENT-OFF* */
147 1151 : 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 *
156 0 : wg_peer_add_command_fn (vlib_main_t * vm,
157 : unformat_input_t * input, vlib_cli_command_t * cmd)
158 : {
159 0 : vnet_main_t *vnm = vnet_get_main ();
160 0 : wg_main_t *wmp = &wg_main;
161 0 : clib_error_t *error = NULL;
162 0 : unformat_input_t _line_input, *line_input = &_line_input;
163 :
164 0 : u8 *public_key_64 = 0;
165 : u8 public_key[NOISE_PUBLIC_KEY_LEN + 1];
166 0 : fib_prefix_t allowed_ip, *allowed_ips = NULL;
167 : ip_prefix_t pfx;
168 0 : ip_address_t ip = ip_address_initializer;
169 0 : u32 portDst = 0, table_id = 0;
170 0 : u32 persistent_keepalive = 0;
171 0 : u32 tun_sw_if_index = ~0;
172 : u32 peer_index;
173 : int rv;
174 :
175 0 : if (!unformat_user (input, unformat_line_input, line_input))
176 0 : return 0;
177 :
178 0 : wg_feature_init (wmp);
179 :
180 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
181 : {
182 0 : if (unformat (line_input, "public-key %s", &public_key_64))
183 : {
184 0 : if (!(key_from_base64 (public_key_64,
185 : NOISE_KEY_LEN_BASE64, public_key)))
186 : {
187 0 : error = clib_error_return (0, "Error parsing private key");
188 0 : goto done;
189 : }
190 : }
191 0 : else if (unformat (line_input, "endpoint %U", unformat_ip_address, &ip))
192 : ;
193 0 : else if (unformat (line_input, "table-id %d", &table_id))
194 : ;
195 0 : else if (unformat (line_input, "dst-port %d", &portDst))
196 : ;
197 0 : else if (unformat (line_input, "persistent-keepalive %d",
198 : &persistent_keepalive))
199 : ;
200 0 : else if (unformat (line_input, "allowed-ip %U",
201 : unformat_ip_prefix, &pfx))
202 : {
203 0 : ip_prefix_to_fib_prefix (&pfx, &allowed_ip);
204 0 : vec_add1 (allowed_ips, allowed_ip);
205 : }
206 0 : else if (unformat (line_input, "%U",
207 : unformat_vnet_sw_interface, vnm, &tun_sw_if_index))
208 : ;
209 : else
210 : {
211 0 : error = clib_error_return (0, "Input error");
212 0 : goto done;
213 : }
214 : }
215 :
216 0 : if (0 == vec_len (allowed_ips))
217 : {
218 0 : error = clib_error_return (0, "Allowed IPs are not specified");
219 0 : goto done;
220 : }
221 :
222 0 : rv = wg_peer_add (tun_sw_if_index, public_key, table_id, &ip_addr_46 (&ip),
223 : allowed_ips, portDst, persistent_keepalive, &peer_index);
224 :
225 0 : switch (rv)
226 : {
227 0 : case VNET_API_ERROR_KEY_LENGTH:
228 0 : error = clib_error_return (0, "Error parsing public key");
229 0 : break;
230 0 : case VNET_API_ERROR_ENTRY_ALREADY_EXISTS:
231 0 : error = clib_error_return (0, "Peer already exist");
232 0 : break;
233 0 : case VNET_API_ERROR_INVALID_SW_IF_INDEX:
234 0 : error = clib_error_return (0, "Tunnel is not specified");
235 0 : break;
236 0 : case VNET_API_ERROR_LIMIT_EXCEEDED:
237 0 : error = clib_error_return (0, "Max peers limit");
238 0 : break;
239 0 : case VNET_API_ERROR_INIT_FAILED:
240 0 : error = clib_error_return (0, "wireguard device parameters is not set");
241 0 : break;
242 0 : case VNET_API_ERROR_INVALID_PROTOCOL:
243 0 : error = clib_error_return (0, "ipv6 not supported yet");
244 0 : break;
245 : }
246 :
247 0 : done:
248 0 : vec_free (public_key_64);
249 0 : vec_free (allowed_ips);
250 0 : unformat_free (line_input);
251 0 : return error;
252 : }
253 :
254 : /* *INDENT-OFF* */
255 1151 : VLIB_CLI_COMMAND (wg_peer_add_command, static) = {
256 : .path = "wireguard peer add",
257 : .short_help =
258 : "wireguard peer add <wg_int> public-key <pub_key_other> "
259 : "endpoint <ip4_dst> allowed-ip <prefix> "
260 : "dst-port [port_dst] persistent-keepalive [keepalive_interval]",
261 : .function = wg_peer_add_command_fn,
262 : };
263 : /* *INDENT-ON* */
264 :
265 : static clib_error_t *
266 0 : wg_peer_remove_command_fn (vlib_main_t * vm,
267 : unformat_input_t * input, vlib_cli_command_t * cmd)
268 : {
269 0 : wg_main_t *wmp = &wg_main;
270 0 : clib_error_t *error = NULL;
271 : u32 peer_index;
272 : int rv;
273 :
274 0 : unformat_input_t _line_input, *line_input = &_line_input;
275 0 : if (!unformat_user (input, unformat_line_input, line_input))
276 0 : return 0;
277 :
278 0 : wg_feature_init (wmp);
279 :
280 0 : if (unformat (line_input, "%d", &peer_index))
281 : ;
282 : else
283 : {
284 0 : error = clib_error_return (0, "Input error");
285 0 : goto done;
286 : }
287 :
288 0 : rv = wg_peer_remove (peer_index);
289 :
290 0 : switch (rv)
291 : {
292 0 : case VNET_API_ERROR_KEY_LENGTH:
293 0 : error = clib_error_return (0, "Error parsing public key");
294 0 : break;
295 : }
296 :
297 0 : done:
298 0 : unformat_free (line_input);
299 0 : return error;
300 : }
301 :
302 : /* *INDENT-OFF* */
303 1151 : VLIB_CLI_COMMAND (wg_peer_remove_command, static) =
304 : {
305 : .path = "wireguard peer remove",
306 : .short_help = "wireguard peer remove <index>",
307 : .function = wg_peer_remove_command_fn,
308 : };
309 : /* *INDENT-ON* */
310 :
311 : static walk_rc_t
312 64 : wg_peer_show_one (index_t peeri, void *arg)
313 : {
314 64 : vlib_cli_output (arg, "%U", format_wg_peer, peeri);
315 :
316 64 : return (WALK_CONTINUE);
317 : }
318 :
319 : static clib_error_t *
320 2 : wg_show_peer_command_fn (vlib_main_t * vm,
321 : unformat_input_t * input, vlib_cli_command_t * cmd)
322 : {
323 2 : wg_peer_walk (wg_peer_show_one, vm);
324 :
325 2 : return NULL;
326 : }
327 :
328 : /* *INDENT-OFF* */
329 1151 : VLIB_CLI_COMMAND (wg_show_peers_command, static) =
330 : {
331 : .path = "show wireguard peer",
332 : .short_help = "show wireguard peer",
333 : .function = wg_show_peer_command_fn,
334 : };
335 : /* *INDENT-ON* */
336 :
337 : static walk_rc_t
338 4 : wg_if_show_one (index_t itfi, void *arg)
339 : {
340 4 : vlib_cli_output (arg, "%U", format_wg_if, itfi);
341 :
342 4 : return (WALK_CONTINUE);
343 : }
344 :
345 : static clib_error_t *
346 2 : wg_show_if_command_fn (vlib_main_t * vm,
347 : unformat_input_t * input, vlib_cli_command_t * cmd)
348 : {
349 2 : wg_main_t *wmp = &wg_main;
350 :
351 2 : wg_feature_init (wmp);
352 :
353 2 : wg_if_walk (wg_if_show_one, vm);
354 :
355 2 : return NULL;
356 : }
357 :
358 : /* *INDENT-OFF* */
359 1151 : VLIB_CLI_COMMAND (wg_show_itfs_command, static) =
360 : {
361 : .path = "show wireguard interface",
362 : .short_help = "show wireguard",
363 : .function = wg_show_if_command_fn,
364 : };
365 :
366 : static clib_error_t *
367 0 : wg_set_async_mode_command_fn (vlib_main_t *vm, unformat_input_t *input,
368 : vlib_cli_command_t *cmd)
369 : {
370 0 : unformat_input_t _line_input, *line_input = &_line_input;
371 0 : int async_enable = 0;
372 :
373 0 : if (!unformat_user (input, unformat_line_input, line_input))
374 0 : return 0;
375 :
376 0 : while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
377 : {
378 0 : if (unformat (line_input, "on"))
379 0 : async_enable = 1;
380 0 : else if (unformat (line_input, "off"))
381 0 : async_enable = 0;
382 : else
383 0 : return (clib_error_return (0, "unknown input '%U'",
384 : format_unformat_error, line_input));
385 : }
386 :
387 0 : wg_set_async_mode (async_enable);
388 :
389 0 : unformat_free (line_input);
390 0 : return (NULL);
391 : }
392 :
393 1151 : VLIB_CLI_COMMAND (wg_set_async_mode_command, static) = {
394 : .path = "set wireguard async mode",
395 : .short_help = "set wireguard async mode on|off",
396 : .function = wg_set_async_mode_command_fn,
397 : };
398 :
399 : static clib_error_t *
400 0 : wg_show_mode_command_fn (vlib_main_t *vm, unformat_input_t *input,
401 : vlib_cli_command_t *cmd)
402 : {
403 0 : vlib_cli_output (vm, "Wireguard mode");
404 :
405 : #define _(v, f, s) \
406 : vlib_cli_output (vm, "\t%s: %s", s, \
407 : (wg_op_mode_is_set_##f () ? "enabled" : "disabled"));
408 0 : foreach_wg_op_mode_flags
409 : #undef _
410 :
411 0 : return (NULL);
412 : }
413 :
414 1151 : VLIB_CLI_COMMAND (wg_show_modemode_command, static) = {
415 : .path = "show wireguard mode",
416 : .short_help = "show wireguard mode",
417 : .function = wg_show_mode_command_fn,
418 : };
419 :
420 : /* *INDENT-ON* */
421 :
422 : /*
423 : * fd.io coding-style-patch-verification: ON
424 : *
425 : * Local Variables:
426 : * eval: (c-set-style "gnu")
427 : * End:
428 : */
|