OpenVPN
networking_iproute2.c
Go to the documentation of this file.
1/*
2 * Networking API implementation for iproute2
3 *
4 * Copyright (C) 2018-2024 Antonio Quartulli <a@unstable.cc>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program (see the file COPYING included with this
17 * distribution); if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#if defined(TARGET_LINUX) && defined(ENABLE_IPROUTE)
26
27#include "syshead.h"
28
29#include "argv.h"
30#include "networking.h"
31#include "misc.h"
32#include "openvpn.h"
33#include "run_command.h"
34#include "socket.h"
35
36#include <stdbool.h>
37#include <netinet/in.h>
38
39int
41{
42 ctx->es = NULL;
43 if (c)
44 {
45 ctx->es = c->es;
46 }
47 ctx->gc = gc_new();
48
49 return 0;
50}
51
52void
54{
55 gc_reset(&ctx->gc);
56}
57
58void
60{
61 gc_free(&ctx->gc);
62}
63
64int
65net_iface_new(openvpn_net_ctx_t *ctx, const char *iface, const char *type,
66 void *arg)
67{
68 struct argv argv = argv_new();
69
70 argv_printf(&argv, "%s link add %s type %s", iproute_path, iface, type);
72 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link add failed");
73
75
76 return 0;
77}
78
79int
80net_iface_type(openvpn_net_ctx_t *ctx, const char *iface,
81 char type[IFACE_TYPE_LEN_MAX])
82{
83 /* not supported by iproute2 */
84 msg(M_WARN, "%s: operation not supported by iproute2 backend", __func__);
85 return -1;
86}
87
88int
89net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
90{
91 struct argv argv = argv_new();
92
93 argv_printf(&argv, "%s link del %s", iproute_path, iface);
94 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip link del failed");
95
97
98 return 0;
99}
100
101int
102net_iface_up(openvpn_net_ctx_t *ctx, const char *iface, bool up)
103{
104 struct argv argv = argv_new();
105
106 argv_printf(&argv, "%s link set dev %s %s", iproute_path, iface,
107 up ? "up" : "down");
109 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
110
111 argv_free(&argv);
112
113 return 0;
114}
115
116int
117net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface, uint32_t mtu)
118{
119 struct argv argv = argv_new();
120
121 argv_printf(&argv, "%s link set dev %s up mtu %d", iproute_path, iface,
122 mtu);
124 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
125
126 argv_free(&argv);
127
128 return 0;
129}
130
131int
132net_addr_ll_set(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
133 uint8_t *addr)
134{
135 struct argv argv = argv_new();
136 int ret = 0;
137
139 "%s link set addr " MAC_FMT " dev %s",
140 iproute_path, MAC_PRINT_ARG(addr), iface);
141
143 if (!openvpn_execve_check(&argv, ctx->es, 0,
144 "Linux ip link set addr failed"))
145 {
146 ret = -1;
147 }
148
149 argv_free(&argv);
150
151 return ret;
152}
153
154int
155net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
156 const in_addr_t *addr, int prefixlen)
157{
158 struct argv argv = argv_new();
159
160 const char *addr_str = print_in_addr_t(*addr, 0, &ctx->gc);
161
162 argv_printf(&argv, "%s addr add dev %s %s/%d", iproute_path, iface,
163 addr_str, prefixlen);
165 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
166
167 argv_free(&argv);
168
169 return 0;
170}
171
172int
173net_addr_v6_add(openvpn_net_ctx_t *ctx, const char *iface,
174 const struct in6_addr *addr, int prefixlen)
175{
176 struct argv argv = argv_new();
177 char *addr_str = (char *)print_in6_addr(*addr, 0, &ctx->gc);
178
179 argv_printf(&argv, "%s -6 addr add %s/%d dev %s", iproute_path, addr_str,
180 prefixlen, iface);
183 "Linux ip -6 addr add failed");
184
185 argv_free(&argv);
186
187 return 0;
188}
189
190int
191net_addr_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
192 const in_addr_t *addr, int prefixlen)
193{
194 struct argv argv = argv_new();
195 const char *addr_str = print_in_addr_t(*addr, 0, &ctx->gc);
196
197 argv_printf(&argv, "%s addr del dev %s %s/%d", iproute_path, iface,
198 addr_str, prefixlen);
199
201 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
202
203 argv_free(&argv);
204
205 return 0;
206}
207
208int
209net_addr_v6_del(openvpn_net_ctx_t *ctx, const char *iface,
210 const struct in6_addr *addr, int prefixlen)
211{
212 struct argv argv = argv_new();
213 char *addr_str = (char *)print_in6_addr(*addr, 0, &ctx->gc);
214
215 argv_printf(&argv, "%s -6 addr del %s/%d dev %s", iproute_path,
216 addr_str, prefixlen, iface);
218 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip -6 addr del failed");
219
220 argv_free(&argv);
221
222 return 0;
223}
224
225int
226net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
227 const in_addr_t *local, const in_addr_t *remote)
228{
229 struct argv argv = argv_new();
230 const char *local_str = print_in_addr_t(*local, 0, &ctx->gc);
231 const char *remote_str = print_in_addr_t(*remote, 0, &ctx->gc);
232
233 argv_printf(&argv, "%s addr add dev %s local %s peer %s", iproute_path,
234 iface, local_str, remote_str);
236 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
237
238 argv_free(&argv);
239
240 return 0;
241}
242
243int
244net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
245 const in_addr_t *local, const in_addr_t *remote)
246{
247 struct argv argv = argv_new();
248 const char *local_str = print_in_addr_t(*local, 0, &ctx->gc);
249 const char *remote_str = print_in_addr_t(*remote, 0, &ctx->gc);
250
251 argv_printf(&argv, "%s addr del dev %s local %s peer %s", iproute_path,
252 iface, local_str, remote_str);
254 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
255
256 argv_free(&argv);
257
258 return 0;
259}
260
261int
262net_route_v4_add(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
263 const in_addr_t *gw, const char *iface, uint32_t table,
264 int metric)
265{
266 struct argv argv = argv_new();
267 const char *dst_str = print_in_addr_t(*dst, 0, &ctx->gc);
268 int ret = 0;
269
270 argv_printf(&argv, "%s route add %s/%d", iproute_path, dst_str, prefixlen);
271
272 if (metric > 0)
273 {
274 argv_printf_cat(&argv, "metric %d", metric);
275 }
276
277 if (iface)
278 {
279 argv_printf_cat(&argv, "dev %s", iface);
280 }
281
282 if (gw)
283 {
284 const char *gw_str = print_in_addr_t(*gw, 0, &ctx->gc);
285
286 argv_printf_cat(&argv, "via %s", gw_str);
287 }
288
290 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route add command failed"))
291 {
292 ret = -1;
293 }
294
295 argv_free(&argv);
296
297 return ret;
298}
299
300int
301net_route_v6_add(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
302 int prefixlen, const struct in6_addr *gw, const char *iface,
303 uint32_t table, int metric)
304{
305 struct argv argv = argv_new();
306 char *dst_str = (char *)print_in6_addr(*dst, 0, &ctx->gc);
307 int ret = 0;
308
309 argv_printf(&argv, "%s -6 route add %s/%d dev %s", iproute_path, dst_str,
310 prefixlen, iface);
311
312 if (gw)
313 {
314 char *gw_str = (char *)print_in6_addr(*gw, 0, &ctx->gc);
315
316 argv_printf_cat(&argv, "via %s", gw_str);
317 }
318
319 if (metric > 0)
320 {
321 argv_printf_cat(&argv, "metric %d", metric);
322 }
323
325 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 add command failed"))
326 {
327 ret = -1;
328 }
329
330 argv_free(&argv);
331
332 return ret;
333}
334
335int
336net_route_v4_del(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
337 const in_addr_t *gw, const char *iface, uint32_t table,
338 int metric)
339{
340 struct argv argv = argv_new();
341 const char *dst_str = print_in_addr_t(*dst, 0, &ctx->gc);
342 int ret = 0;
343
344 argv_printf(&argv, "%s route del %s/%d", iproute_path, dst_str, prefixlen);
345
346 if (metric > 0)
347 {
348 argv_printf_cat(&argv, "metric %d", metric);
349 }
350
352 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route delete command failed"))
353 {
354 ret = -1;
355 }
356
357 argv_free(&argv);
358
359 return ret;
360}
361
362int
363net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
364 int prefixlen, const struct in6_addr *gw, const char *iface,
365 uint32_t table, int metric)
366{
367 struct argv argv = argv_new();
368 char *dst_str = (char *)print_in6_addr(*dst, 0, &ctx->gc);
369 int ret = 0;
370
371 argv_printf(&argv, "%s -6 route del %s/%d dev %s", iproute_path, dst_str,
372 prefixlen, iface);
373
374 if (gw)
375 {
376 char *gw_str = (char *)print_in6_addr(*gw, 0, &ctx->gc);
377
378 argv_printf_cat(&argv, "via %s", gw_str);
379 }
380
381 if (metric > 0)
382 {
383 argv_printf_cat(&argv, "metric %d", metric);
384 }
385
387 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 del command failed"))
388 {
389 ret = -1;
390 }
391
392 argv_free(&argv);
393
394 return ret;
395}
396
397/*
398 * The following functions are not implemented in the iproute backend as it
399 * uses the sitnl implementation from networking_sitnl.c.
400 *
401 * int
402 * net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
403 * in_addr_t *best_gw, char *best_iface)
404 *
405 * int
406 * net_route_v6_best_gw(const struct in6_addr *dst,
407 * struct in6_addr *best_gw, char *best_iface)
408 */
409
410#endif /* ENABLE_IPROUTE && TARGET_LINUX */
void argv_msg(const int msglev, const struct argv *a)
Write the arguments stored in a struct argv via the msg() command.
Definition argv.c:243
void argv_free(struct argv *a)
Frees all memory allocations allocated by the struct argv related functions.
Definition argv.c:102
bool argv_printf(struct argv *argres, const char *format,...)
printf() variant which populates a struct argv.
Definition argv.c:440
bool argv_printf_cat(struct argv *argres, const char *format,...)
printf() inspired argv concatenation.
Definition argv.c:464
struct argv argv_new(void)
Allocates a new struct argv and ensures it is initialised.
Definition argv.c:88
static void gc_reset(struct gc_arena *a)
Definition buffer.h:1046
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
static struct gc_arena gc_new(void)
Definition buffer.h:1025
#define M_INFO
Definition errlevel.h:55
#define D_ROUTE
Definition errlevel.h:80
#define MAC_PRINT_ARG(_mac)
Definition misc.h:227
#define MAC_FMT
Definition misc.h:225
static void net_ctx_reset(openvpn_net_ctx_t *ctx)
Definition networking.h:57
void * openvpn_net_iface_t
Definition networking.h:40
#define IFACE_TYPE_LEN_MAX
Definition networking.h:26
static int net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
Definition networking.h:48
static void net_ctx_free(openvpn_net_ctx_t *ctx)
Definition networking.h:63
void * openvpn_net_ctx_t
Definition networking.h:39
#define msg(flags,...)
Definition error.h:144
#define M_WARN
Definition error.h:91
int openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message)
#define S_FATAL
Definition run_command.h:46
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2994
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2974
Definition argv.h:35
Contains all state information for one tunnel.
Definition openvpn.h:474
struct env_set * es
Set of environment variables.
Definition openvpn.h:496
struct gc_arena * gc
Definition env_set.h:43
static char * iface