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 
39 int
40 net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
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 
52 void
54 {
55  gc_reset(&ctx->gc);
56 }
57 
58 void
60 {
61  gc_free(&ctx->gc);
62 }
63 
64 int
65 net_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);
71  argv_msg(M_INFO, &argv);
72  openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link add failed");
73 
74  argv_free(&argv);
75 
76  return 0;
77 }
78 
79 int
80 net_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 
88 int
89 net_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 
96  argv_free(&argv);
97 
98  return 0;
99 }
100 
101 int
102 net_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");
108  argv_msg(M_INFO, &argv);
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 
116 int
117 net_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);
123  argv_msg(M_INFO, &argv);
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 
131 int
132 net_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 
138  argv_printf(&argv,
139  "%s link set addr " MAC_FMT " dev %s",
140  iproute_path, MAC_PRINT_ARG(addr), iface);
141 
142  argv_msg(M_INFO, &argv);
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 
154 int
155 net_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);
164  argv_msg(M_INFO, &argv);
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 
172 int
173 net_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);
181  argv_msg(M_INFO, &argv);
182  openvpn_execve_check(&argv, ctx->es, S_FATAL,
183  "Linux ip -6 addr add failed");
184 
185  argv_free(&argv);
186 
187  return 0;
188 }
189 
190 int
191 net_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 
200  argv_msg(M_INFO, &argv);
201  openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
202 
203  argv_free(&argv);
204 
205  return 0;
206 }
207 
208 int
209 net_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);
217  argv_msg(M_INFO, &argv);
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 
225 int
226 net_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);
235  argv_msg(M_INFO, &argv);
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 
243 int
244 net_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);
253  argv_msg(M_INFO, &argv);
254  openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
255 
256  argv_free(&argv);
257 
258  return 0;
259 }
260 
261 int
262 net_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 
289  argv_msg(D_ROUTE, &argv);
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 
300 int
301 net_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 
324  argv_msg(D_ROUTE, &argv);
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 
335 int
336 net_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 
351  argv_msg(D_ROUTE, &argv);
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 
362 int
363 net_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 
386  argv_msg(D_ROUTE, &argv);
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 int
398 net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
399  in_addr_t *best_gw, char *best_iface)
400 {
401  best_iface[0] = '\0';
402 
403  FILE *fp = fopen("/proc/net/route", "r");
404  if (!fp)
405  {
406  return -1;
407  }
408 
409  char line[256];
410  int count = 0;
411  unsigned int lowest_metric = UINT_MAX;
412  while (fgets(line, sizeof(line), fp) != NULL)
413  {
414  if (count)
415  {
416  unsigned int net_x = 0;
417  unsigned int mask_x = 0;
418  unsigned int gw_x = 0;
419  unsigned int metric = 0;
420  unsigned int flags = 0;
421  char name[16];
422  name[0] = '\0';
423 
424  const int np = sscanf(line, "%15s\t%x\t%x\t%x\t%*s\t%*s\t%d\t%x",
425  name, &net_x, &gw_x, &flags, &metric,
426  &mask_x);
427 
428  if (np == 6 && (flags & IFF_UP))
429  {
430  const in_addr_t net = ntohl(net_x);
431  const in_addr_t mask = ntohl(mask_x);
432  const in_addr_t gw = ntohl(gw_x);
433 
434  if (!net && !mask && metric < lowest_metric)
435  {
436  *best_gw = gw;
437  strcpy(best_iface, name);
438  lowest_metric = metric;
439  }
440  }
441  }
442  ++count;
443  }
444  fclose(fp);
445 
446  return 0;
447 }
448 
449 /*
450  * The following function is not implemented in the iproute backend as it
451  * uses the sitnl implementation from networking_sitnl.c.
452  *
453  * int
454  * net_route_v6_best_gw(const struct in6_addr *dst,
455  * struct in6_addr *best_gw, char *best_iface)
456  */
457 
458 #endif /* ENABLE_IPROUTE && TARGET_LINUX */
M_INFO
#define M_INFO
Definition: errlevel.h:55
env_set::gc
struct gc_arena * gc
Definition: env_set.h:43
gc_new
static struct gc_arena gc_new(void)
Definition: buffer.h:1030
run_command.h
networking.h
IFACE_TYPE_LEN_MAX
#define IFACE_TYPE_LEN_MAX
Definition: networking.h:26
argv
Definition: argv.h:35
context
Contains all state information for one tunnel.
Definition: openvpn.h:476
D_ROUTE
#define D_ROUTE
Definition: errlevel.h:80
argv_printf_cat
bool argv_printf_cat(struct argv *argres, const char *format,...)
printf() inspired argv concatenation.
Definition: argv.c:464
argv_free
void argv_free(struct argv *a)
Frees all memory allocations allocated by the struct argv related functions.
Definition: argv.c:102
openvpn.h
openvpn_net_ctx_t
void * openvpn_net_ctx_t
Definition: networking.h:28
gc_reset
static void gc_reset(struct gc_arena *a)
Definition: buffer.h:1051
net_ctx_init
static int net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
Definition: networking.h:48
np
static const char * np(const char *str)
Definition: multi-auth.c:146
openvpn_execve_check
int openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message)
Definition: run_command.c:193
MAC_PRINT_ARG
#define MAC_PRINT_ARG(_mac)
Definition: misc.h:214
print_in6_addr
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
Definition: socket.c:2924
argv.h
MAC_FMT
#define MAC_FMT
Definition: misc.h:212
misc.h
M_WARN
#define M_WARN
Definition: error.h:91
net_ctx_reset
static void net_ctx_reset(openvpn_net_ctx_t *ctx)
Definition: networking.h:57
iface
static char * iface
Definition: test_networking.c:7
print_in_addr_t
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition: socket.c:2904
net_ctx_free
static void net_ctx_free(openvpn_net_ctx_t *ctx)
Definition: networking.h:63
syshead.h
argv_new
struct argv argv_new(void)
Allocates a new struct argv and ensures it is initialised.
Definition: argv.c:88
argv_printf
bool argv_printf(struct argv *argres, const char *format,...)
printf() variant which populates a struct argv.
Definition: argv.c:440
context::es
struct env_set * es
Set of environment variables.
Definition: openvpn.h:499
gc_free
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1038
socket.h
argv_msg
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
config.h
S_FATAL
#define S_FATAL
Definition: run_command.h:46
openvpn_net_iface_t
void * openvpn_net_iface_t
Definition: networking.h:40
msg
#define msg(flags,...)
Definition: error.h:144