OpenVPN
networking_iproute2.c
Go to the documentation of this file.
1/*
2 * Networking API implementation for iproute2
3 *
4 * Copyright (C) 2018-2025 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#if defined(TARGET_LINUX) && defined(ENABLE_IPROUTE)
25
26#include "syshead.h"
27
28#include "argv.h"
29#include "networking.h"
30#include "misc.h"
31#include "openvpn.h"
32#include "run_command.h"
33#include "socket_util.h"
34
35#include <stdbool.h>
36#include <netinet/in.h>
37
38int
40{
41 ctx->es = NULL;
42 if (c)
43 {
44 ctx->es = c->es;
45 }
46 ctx->gc = gc_new();
47
48 return 0;
49}
50
51void
53{
54 gc_reset(&ctx->gc);
55}
56
57void
59{
60 gc_free(&ctx->gc);
61}
62
63int
64net_iface_new(openvpn_net_ctx_t *ctx, const char *iface, const char *type, void *arg)
65{
66 struct argv argv = argv_new();
67
68 argv_printf(&argv, "%s link add %s type %s", iproute_path, iface, type);
70 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link add failed");
71
73
74 return 0;
75}
76
77int
78net_iface_type(openvpn_net_ctx_t *ctx, const char *iface, char type[IFACE_TYPE_LEN_MAX])
79{
80 /* not supported by iproute2 */
81 msg(M_WARN, "%s: operation not supported by iproute2 backend", __func__);
82 return -1;
83}
84
85int
86net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
87{
88 struct argv argv = argv_new();
89
90 argv_printf(&argv, "%s link del %s", iproute_path, iface);
91 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip link del failed");
92
94
95 return 0;
96}
97
98int
99net_iface_up(openvpn_net_ctx_t *ctx, const char *iface, bool up)
100{
101 struct argv argv = argv_new();
102
103 argv_printf(&argv, "%s link set dev %s %s", iproute_path, iface, up ? "up" : "down");
105 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
106
107 argv_free(&argv);
108
109 return 0;
110}
111
112int
113net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface, uint32_t mtu)
114{
115 struct argv argv = argv_new();
116
117 argv_printf(&argv, "%s link set dev %s up mtu %d", iproute_path, iface, mtu);
119 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
120
121 argv_free(&argv);
122
123 return 0;
124}
125
126int
127net_addr_ll_set(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface, uint8_t *addr)
128{
129 struct argv argv = argv_new();
130 int ret = 0;
131
132 argv_printf(&argv, "%s link set addr " MAC_FMT " dev %s", iproute_path, MAC_PRINT_ARG(addr),
133 iface);
134
136 if (!openvpn_execve_check(&argv, ctx->es, 0, "Linux ip link set addr failed"))
137 {
138 ret = -1;
139 }
140
141 argv_free(&argv);
142
143 return ret;
144}
145
146int
147net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *addr, int prefixlen)
148{
149 struct argv argv = argv_new();
150
151 const char *addr_str = print_in_addr_t(*addr, 0, &ctx->gc);
152
153 argv_printf(&argv, "%s addr add dev %s %s/%d", iproute_path, iface, addr_str, prefixlen);
155 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
156
157 argv_free(&argv);
158
159 return 0;
160}
161
162int
163net_addr_v6_add(openvpn_net_ctx_t *ctx, const char *iface, const struct in6_addr *addr,
164 int prefixlen)
165{
166 struct argv argv = argv_new();
167 char *addr_str = (char *)print_in6_addr(*addr, 0, &ctx->gc);
168
169 argv_printf(&argv, "%s -6 addr add %s/%d dev %s", iproute_path, addr_str, prefixlen, iface);
171 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip -6 addr add failed");
172
173 argv_free(&argv);
174
175 return 0;
176}
177
178int
179net_addr_v4_del(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *addr, int prefixlen)
180{
181 struct argv argv = argv_new();
182 const char *addr_str = print_in_addr_t(*addr, 0, &ctx->gc);
183
184 argv_printf(&argv, "%s addr del dev %s %s/%d", iproute_path, iface, addr_str, prefixlen);
185
187 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
188
189 argv_free(&argv);
190
191 return 0;
192}
193
194int
195net_addr_v6_del(openvpn_net_ctx_t *ctx, const char *iface, const struct in6_addr *addr,
196 int prefixlen)
197{
198 struct argv argv = argv_new();
199 char *addr_str = (char *)print_in6_addr(*addr, 0, &ctx->gc);
200
201 argv_printf(&argv, "%s -6 addr del %s/%d dev %s", iproute_path, addr_str, prefixlen, iface);
203 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip -6 addr del failed");
204
205 argv_free(&argv);
206
207 return 0;
208}
209
210int
211net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *local,
212 const in_addr_t *remote)
213{
214 struct argv argv = argv_new();
215 const char *local_str = print_in_addr_t(*local, 0, &ctx->gc);
216 const char *remote_str = print_in_addr_t(*remote, 0, &ctx->gc);
217
218 argv_printf(&argv, "%s addr add dev %s local %s peer %s", iproute_path, iface, local_str,
219 remote_str);
221 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
222
223 argv_free(&argv);
224
225 return 0;
226}
227
228int
229net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx, const char *iface, const in_addr_t *local,
230 const in_addr_t *remote)
231{
232 struct argv argv = argv_new();
233 const char *local_str = print_in_addr_t(*local, 0, &ctx->gc);
234 const char *remote_str = print_in_addr_t(*remote, 0, &ctx->gc);
235
236 argv_printf(&argv, "%s addr del dev %s local %s peer %s", iproute_path, iface, local_str,
237 remote_str);
239 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
240
241 argv_free(&argv);
242
243 return 0;
244}
245
246int
247net_route_v4_add(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen, const in_addr_t *gw,
248 const char *iface, uint32_t table, int metric)
249{
250 struct argv argv = argv_new();
251 const char *dst_str = print_in_addr_t(*dst, 0, &ctx->gc);
252 int ret = 0;
253
254 argv_printf(&argv, "%s route add %s/%d", iproute_path, dst_str, prefixlen);
255
256 if (metric > 0)
257 {
258 argv_printf_cat(&argv, "metric %d", metric);
259 }
260
261 if (iface)
262 {
263 argv_printf_cat(&argv, "dev %s", iface);
264 }
265
266 if (gw)
267 {
268 const char *gw_str = print_in_addr_t(*gw, 0, &ctx->gc);
269
270 argv_printf_cat(&argv, "via %s", gw_str);
271 }
272
274 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route add command failed"))
275 {
276 ret = -1;
277 }
278
279 argv_free(&argv);
280
281 return ret;
282}
283
284int
285net_route_v6_add(openvpn_net_ctx_t *ctx, const struct in6_addr *dst, int prefixlen,
286 const struct in6_addr *gw, const char *iface, uint32_t table, int metric)
287{
288 struct argv argv = argv_new();
289 char *dst_str = (char *)print_in6_addr(*dst, 0, &ctx->gc);
290 int ret = 0;
291
292 argv_printf(&argv, "%s -6 route add %s/%d dev %s", iproute_path, dst_str, prefixlen, iface);
293
294 if (gw)
295 {
296 char *gw_str = (char *)print_in6_addr(*gw, 0, &ctx->gc);
297
298 argv_printf_cat(&argv, "via %s", gw_str);
299 }
300
301 if (metric > 0)
302 {
303 argv_printf_cat(&argv, "metric %d", metric);
304 }
305
307 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 add command failed"))
308 {
309 ret = -1;
310 }
311
312 argv_free(&argv);
313
314 return ret;
315}
316
317int
318net_route_v4_del(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen, const in_addr_t *gw,
319 const char *iface, uint32_t table, int metric)
320{
321 struct argv argv = argv_new();
322 const char *dst_str = print_in_addr_t(*dst, 0, &ctx->gc);
323 int ret = 0;
324
325 argv_printf(&argv, "%s route del %s/%d", iproute_path, dst_str, prefixlen);
326
327 if (metric > 0)
328 {
329 argv_printf_cat(&argv, "metric %d", metric);
330 }
331
333 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route delete command failed"))
334 {
335 ret = -1;
336 }
337
338 argv_free(&argv);
339
340 return ret;
341}
342
343int
344net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst, int prefixlen,
345 const struct in6_addr *gw, const char *iface, uint32_t table, int metric)
346{
347 struct argv argv = argv_new();
348 char *dst_str = (char *)print_in6_addr(*dst, 0, &ctx->gc);
349 int ret = 0;
350
351 argv_printf(&argv, "%s -6 route del %s/%d dev %s", iproute_path, dst_str, prefixlen, iface);
352
353 if (gw)
354 {
355 char *gw_str = (char *)print_in6_addr(*gw, 0, &ctx->gc);
356
357 argv_printf_cat(&argv, "via %s", gw_str);
358 }
359
360 if (metric > 0)
361 {
362 argv_printf_cat(&argv, "metric %d", metric);
363 }
364
366 if (!openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 del command failed"))
367 {
368 ret = -1;
369 }
370
371 argv_free(&argv);
372
373 return ret;
374}
375
376/*
377 * The following functions are not implemented in the iproute backend as it
378 * uses the sitnl implementation from networking_sitnl.c.
379 *
380 * int
381 * net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
382 * in_addr_t *best_gw, char *best_iface)
383 *
384 * int
385 * net_route_v6_best_gw(const struct in6_addr *dst,
386 * struct in6_addr *best_gw, char *best_iface)
387 */
388
389#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:242
void argv_free(struct argv *a)
Frees all memory allocations allocated by the struct argv related functions.
Definition argv.c:101
bool argv_printf(struct argv *argres, const char *format,...)
printf() variant which populates a struct argv.
Definition argv.c:438
bool argv_printf_cat(struct argv *argres, const char *format,...)
printf() inspired argv concatenation.
Definition argv.c:462
struct argv argv_new(void)
Allocates a new struct argv and ensures it is initialised.
Definition argv.c:87
static void gc_reset(struct gc_arena *a)
Definition buffer.h:1028
static void gc_free(struct gc_arena *a)
Definition buffer.h:1015
static struct gc_arena gc_new(void)
Definition buffer.h:1007
#define M_INFO
Definition errlevel.h:54
#define D_ROUTE
Definition errlevel.h:79
#define MAC_PRINT_ARG(_mac)
Definition misc.h:222
#define MAC_FMT
Definition misc.h:220
static void net_ctx_reset(openvpn_net_ctx_t *ctx)
Definition networking.h:56
void * openvpn_net_iface_t
Definition networking.h:39
#define IFACE_TYPE_LEN_MAX
Definition networking.h:25
static int net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
Definition networking.h:47
static void net_ctx_free(openvpn_net_ctx_t *ctx)
Definition networking.h:62
void * openvpn_net_ctx_t
Definition networking.h:38
#define msg(flags,...)
Definition error.h:150
#define M_WARN
Definition error.h:90
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:50
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
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:499
struct gc_arena * gc
Definition env_set.h:44
static char * iface