Browse code

implement networking API for iproute2

iproute2 is the first user of the new networking API and
its one of the two currently supported functionalities on
Linux (the other being net-tools).

This patch simply copies the current code from tun.c/route.c
to networking_iproute2.c without introducing any funcional
change to the code.

Signed-off-by: Antonio Quartulli <a@unstable.cc>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <20181219050118.6568-2-a@unstable.cc>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg18031.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Antonio Quartulli authored on 2018/12/19 14:01:12
Showing 4 changed files
... ...
@@ -80,7 +80,7 @@ openvpn_SOURCES = \
80 80
 	mtu.c mtu.h \
81 81
 	mudp.c mudp.h \
82 82
 	multi.c multi.h \
83
-	networking.h \
83
+	networking_iproute2.c networking_iproute2.h networking.h \
84 84
 	ntlm.c ntlm.h \
85 85
 	occ.c occ.h \
86 86
 	openssl_compat.h \
... ...
@@ -34,7 +34,7 @@ struct context;
34 34
 #ifdef ENABLE_SITNL
35 35
 #include "networking_sitnl.h"
36 36
 #elif ENABLE_IPROUTE
37
-#include "networking_ip.h"
37
+#include "networking_iproute2.h"
38 38
 #else
39 39
 /* define mock types to ensure code builds on any platform */
40 40
 typedef void * openvpn_net_ctx_t;
41 41
new file mode 100644
... ...
@@ -0,0 +1,386 @@
0
+/*
1
+ *  Networking API implementation for iproute2
2
+ *
3
+ *  Copyright (C) 2018 Antonio Quartulli <a@unstable.cc>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2
7
+ *  as published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program (see the file COPYING included with this
16
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
17
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
+ */
19
+
20
+#ifdef HAVE_CONFIG_H
21
+#include "config.h"
22
+#elif defined(_MSC_VER)
23
+#include "config-msvc.h"
24
+#endif
25
+
26
+#if defined(TARGET_LINUX) && defined(ENABLE_IPROUTE)
27
+
28
+#include "syshead.h"
29
+
30
+#include "networking.h"
31
+#include "networking_iproute2.h"
32
+#include "misc.h"
33
+#include "openvpn.h"
34
+#include "run_command.h"
35
+#include "socket.h"
36
+
37
+#include <stdbool.h>
38
+#include <netinet/in.h>
39
+
40
+int
41
+net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
42
+{
43
+    ctx->es = NULL;
44
+    if (c)
45
+        ctx->es = c->es;
46
+
47
+    return 0;
48
+}
49
+
50
+int
51
+net_iface_up(openvpn_net_ctx_t *ctx, const char *iface, bool up)
52
+{
53
+    struct argv argv = argv_new();
54
+
55
+    argv_printf(&argv, "%s link set dev %s %s", iproute_path, iface,
56
+                up ? "up" : "down");
57
+    argv_msg(M_INFO, &argv);
58
+    openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
59
+
60
+    argv_reset(&argv);
61
+
62
+    return 0;
63
+}
64
+
65
+int
66
+net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface, uint32_t mtu)
67
+{
68
+    struct argv argv = argv_new();
69
+
70
+    argv_printf(&argv, "%s link set dev %s up mtu %d", iproute_path, iface,
71
+                mtu);
72
+    argv_msg(M_INFO, &argv);
73
+    openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
74
+
75
+    return 0;
76
+}
77
+
78
+int
79
+net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
80
+                const in_addr_t *addr, int prefixlen,
81
+                const in_addr_t *broadcast)
82
+{
83
+    struct argv argv = argv_new();
84
+
85
+    char *addr_str = (char *)print_in_addr_t(*addr, 0, NULL);
86
+    char *brd_str = (char *)print_in_addr_t(*broadcast, 0, NULL);
87
+
88
+    argv_printf(&argv, "%s addr add dev %s %s/%d broadcast %s", iproute_path,
89
+                iface, addr_str, prefixlen, brd_str);
90
+    argv_msg(M_INFO, &argv);
91
+    openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
92
+
93
+    free(addr_str);
94
+    free(brd_str);
95
+
96
+    argv_reset(&argv);
97
+
98
+    return 0;
99
+}
100
+
101
+int
102
+net_addr_v6_add(openvpn_net_ctx_t *ctx, const char *iface,
103
+                const struct in6_addr *addr, int prefixlen)
104
+{
105
+    struct argv argv = argv_new();
106
+    char *addr_str = (char *)print_in6_addr(*addr, 0, NULL);
107
+
108
+    argv_printf(&argv, "%s -6 addr add %s/%d dev %s", iproute_path, addr_str,
109
+                prefixlen, iface);
110
+    argv_msg(M_INFO, &argv);
111
+    openvpn_execve_check(&argv, ctx->es, S_FATAL,
112
+                         "Linux ip -6 addr add failed");
113
+
114
+    free(addr_str);
115
+
116
+    argv_reset(&argv);
117
+
118
+    return 0;
119
+}
120
+
121
+int
122
+net_addr_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
123
+                const in_addr_t *addr, int prefixlen)
124
+{
125
+    struct argv argv = argv_new();
126
+    char *addr_str = (char *)print_in_addr_t(*addr, 0, NULL);
127
+
128
+    argv_printf(&argv, "%s addr del dev %s %s/%d", iproute_path, iface,
129
+                addr_str, prefixlen);
130
+
131
+    argv_msg(M_INFO, &argv);
132
+    openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
133
+
134
+    free(addr_str);
135
+
136
+    argv_reset(&argv);
137
+
138
+    return 0;
139
+}
140
+
141
+int
142
+net_addr_v6_del(openvpn_net_ctx_t *ctx, const char *iface,
143
+                const struct in6_addr *addr, int prefixlen)
144
+{
145
+    struct argv argv = argv_new();
146
+    char *addr_str = (char *)print_in6_addr(*addr, 0, NULL);
147
+
148
+    argv_printf(&argv, "%s -6 addr del %s/%d dev %s", iproute_path,
149
+                addr_str, prefixlen, iface);
150
+    argv_msg(M_INFO, &argv);
151
+    openvpn_execve_check(&argv, ctx->es, 0, "Linux ip -6 addr del failed");
152
+
153
+    free(addr_str);
154
+
155
+    argv_reset(&argv);
156
+
157
+    return 0;
158
+}
159
+
160
+int
161
+net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
162
+                    const in_addr_t *local, const in_addr_t *remote)
163
+{
164
+    struct argv argv = argv_new();
165
+    char *local_str = (char *)print_in_addr_t(*local, 0, NULL);
166
+    char *remote_str = (char *)print_in_addr_t(*remote, 0, NULL);
167
+
168
+    argv_printf(&argv, "%s addr add dev %s local %s peer %s", iproute_path,
169
+                iface, local_str, remote_str);
170
+    argv_msg(M_INFO, &argv);
171
+    openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
172
+
173
+    free(local_str);
174
+    free(remote_str);
175
+
176
+    argv_reset(&argv);
177
+
178
+    return 0;
179
+}
180
+
181
+int
182
+net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
183
+                    const in_addr_t *local, const in_addr_t *remote)
184
+{
185
+    struct argv argv = argv_new();
186
+    char *local_str = (char *)print_in_addr_t(*local, 0, NULL);
187
+    char *remote_str = (char *)print_in_addr_t(*remote, 0, NULL);
188
+
189
+    argv_printf(&argv, "%s addr del dev %s local %s peer %s", iproute_path,
190
+                iface, local_str, remote_str);
191
+    argv_msg(M_INFO, &argv);
192
+    openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
193
+
194
+    free(local_str);
195
+    free(remote_str);
196
+
197
+    argv_reset(&argv);
198
+
199
+    return 0;
200
+}
201
+
202
+int
203
+net_route_v4_add(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
204
+                 const in_addr_t *gw, const char *iface, uint32_t table,
205
+                 int metric)
206
+{
207
+    struct argv argv = argv_new();
208
+    char *dst_str = (char *)print_in_addr_t(*dst, 0, NULL);
209
+
210
+    argv_printf(&argv, "%s route add %s/%d", iproute_path, dst_str, prefixlen);
211
+
212
+    if (metric > 0)
213
+        argv_printf_cat(&argv, "metric %d", metric);
214
+
215
+    if (iface)
216
+        argv_printf_cat(&argv, "dev %s", iface);
217
+
218
+    if (gw)
219
+    {
220
+        char *gw_str = (char *)print_in_addr_t(*gw, 0, NULL);
221
+
222
+        argv_printf_cat(&argv, "via %s", gw_str);
223
+
224
+        free(gw_str);
225
+    }
226
+
227
+    argv_msg(D_ROUTE, &argv);
228
+    openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route add command failed");
229
+
230
+    free(dst_str);
231
+
232
+    argv_reset(&argv);
233
+
234
+    return 0;
235
+}
236
+
237
+int
238
+net_route_v6_add(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
239
+                 int prefixlen, const struct in6_addr *gw, const char *iface,
240
+                 uint32_t table, int metric)
241
+{
242
+    struct argv argv = argv_new();
243
+    char *dst_str = (char *)print_in6_addr(*dst, 0, NULL);
244
+
245
+    argv_printf(&argv, "%s -6 route add %s/%d dev %s", iproute_path, dst_str,
246
+                prefixlen, iface);
247
+
248
+    if (gw)
249
+    {
250
+        char *gw_str = (char *)print_in6_addr(*gw, 0, NULL);
251
+
252
+        argv_printf_cat(&argv, "via %s", gw_str);
253
+
254
+        free(gw_str);
255
+    }
256
+
257
+    if (metric > 0)
258
+        argv_printf_cat(&argv, "metric %d", metric);
259
+
260
+    argv_msg(D_ROUTE, &argv);
261
+    openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 add command failed");
262
+
263
+    free(dst_str);
264
+
265
+    argv_reset(&argv);
266
+
267
+    return 0;
268
+}
269
+
270
+int
271
+net_route_v4_del(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
272
+                 const in_addr_t *gw, const char *iface, uint32_t table,
273
+                 int metric)
274
+{
275
+    struct argv argv = argv_new();
276
+    char *dst_str = (char *)print_in_addr_t(*dst, 0, NULL);
277
+
278
+    argv_printf(&argv, "%s route del %s/%d", iproute_path, dst_str, prefixlen);
279
+
280
+    if (metric > 0)
281
+        argv_printf_cat(&argv, "metric %d", metric);
282
+
283
+    argv_msg(D_ROUTE, &argv);
284
+    openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route delete command failed");
285
+
286
+    free(dst_str);
287
+
288
+    argv_reset(&argv);
289
+
290
+    return 0;
291
+}
292
+
293
+int
294
+net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
295
+                 int prefixlen, const struct in6_addr *gw, const char *iface,
296
+                 uint32_t table, int metric)
297
+{
298
+    struct argv argv = argv_new();
299
+    char *dst_str = (char *)print_in6_addr(*dst, 0, NULL);
300
+
301
+    argv_printf(&argv, "%s -6 route del %s/%d dev %s", iproute_path, dst_str,
302
+                prefixlen, iface);
303
+
304
+    if (gw)
305
+    {
306
+        char *gw_str = (char *)print_in6_addr(*gw, 0, NULL);
307
+
308
+        argv_printf_cat(&argv, "via %s", gw_str);
309
+
310
+        free(gw_str);
311
+    }
312
+
313
+    if (metric > 0)
314
+        argv_printf_cat(&argv, "metric %d", metric);
315
+
316
+    argv_msg(D_ROUTE, &argv);
317
+    openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 del command failed");
318
+
319
+    free(dst_str);
320
+
321
+    argv_reset(&argv);
322
+
323
+    return 0;
324
+}
325
+
326
+int
327
+net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
328
+                     int prefixlen, in_addr_t *best_gw, char *best_iface)
329
+{
330
+    best_iface[0] = '\0';
331
+
332
+    FILE *fp = fopen("/proc/net/route", "r");
333
+    if (!fp)
334
+        return -1;
335
+
336
+    char line[256];
337
+    int count = 0;
338
+    unsigned int lowest_metric = UINT_MAX;
339
+    while (fgets(line, sizeof(line), fp) != NULL)
340
+    {
341
+        if (count)
342
+        {
343
+            unsigned int net_x = 0;
344
+            unsigned int mask_x = 0;
345
+            unsigned int gw_x = 0;
346
+            unsigned int metric = 0;
347
+            unsigned int flags = 0;
348
+            char name[16];
349
+            name[0] = '\0';
350
+
351
+            const int np = sscanf(line, "%15s\t%x\t%x\t%x\t%*s\t%*s\t%d\t%x",
352
+                                  name, &net_x, &gw_x, &flags, &metric,
353
+                                  &mask_x);
354
+
355
+            if (np == 6 && (flags & IFF_UP))
356
+            {
357
+                const in_addr_t net = ntohl(net_x);
358
+                const in_addr_t mask = ntohl(mask_x);
359
+                const in_addr_t gw = ntohl(gw_x);
360
+
361
+                if (!net && !mask && metric < lowest_metric)
362
+                {
363
+                    *best_gw = gw;
364
+                    strcpy(best_iface, name);
365
+                    lowest_metric = metric;
366
+                }
367
+            }
368
+        }
369
+        ++count;
370
+    }
371
+    fclose(fp);
372
+
373
+    return 0;
374
+}
375
+
376
+/*
377
+ * The following function is not implemented in the iproute backend as it
378
+ * already uses netlink in route.c.
379
+ *
380
+ * int
381
+ * net_route_v6_best_gw(const struct in6_addr *dst, int prefixlen,
382
+ *                      struct in6_addr *best_gw, char *best_iface)
383
+ */
384
+
385
+#endif /* ENABLE_IPROUTE && TARGET_LINUX */
0 386
new file mode 100644
... ...
@@ -0,0 +1,36 @@
0
+/*
1
+ *  Generic interface to platform specific networking code
2
+ *
3
+ *  Copyright (C) 2016-2018 Antonio Quartulli <a@unstable.cc>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2
7
+ *  as published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program (see the file COPYING included with this
16
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
17
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
+ */
19
+
20
+
21
+#ifndef NETWORKING_IP_H_
22
+#define NETWORKING_IP_H_
23
+
24
+#include "env_set.h"
25
+
26
+typedef char openvpn_net_iface_t;
27
+
28
+struct openvpn_net_ctx
29
+{
30
+    struct env_set *es;
31
+};
32
+
33
+typedef struct openvpn_net_ctx openvpn_net_ctx_t;
34
+
35
+#endif /* NETWORKING_IP_H_ */