1 /*
2 * Networking API implementation for iproute2
3 *
4 * Copyright (C) 2018 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 #elif defined(_MSC_VER)
24 #include "config-msvc.h"
25 #endif
26
27 #if defined(TARGET_LINUX) && defined(ENABLE_IPROUTE)
28
29 #include "syshead.h"
30
31 #include "argv.h"
32 #include "networking.h"
33 #include "misc.h"
34 #include "openvpn.h"
35 #include "run_command.h"
36 #include "socket.h"
37
38 #include <stdbool.h>
39 #include <netinet/in.h>
40
41 int
net_ctx_init(struct context * c,openvpn_net_ctx_t * ctx)42 net_ctx_init(struct context *c, openvpn_net_ctx_t *ctx)
43 {
44 ctx->es = NULL;
45 if (c)
46 {
47 ctx->es = c->es;
48 }
49 ctx->gc = gc_new();
50
51 return 0;
52 }
53
54 void
net_ctx_reset(openvpn_net_ctx_t * ctx)55 net_ctx_reset(openvpn_net_ctx_t *ctx)
56 {
57 gc_reset(&ctx->gc);
58 }
59
60 void
net_ctx_free(openvpn_net_ctx_t * ctx)61 net_ctx_free(openvpn_net_ctx_t *ctx)
62 {
63 gc_free(&ctx->gc);
64 }
65
66 int
net_iface_up(openvpn_net_ctx_t * ctx,const char * iface,bool up)67 net_iface_up(openvpn_net_ctx_t *ctx, const char *iface, bool up)
68 {
69 struct argv argv = argv_new();
70
71 argv_printf(&argv, "%s link set dev %s %s", iproute_path, iface,
72 up ? "up" : "down");
73 argv_msg(M_INFO, &argv);
74 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
75
76 argv_free(&argv);
77
78 return 0;
79 }
80
81 int
net_iface_mtu_set(openvpn_net_ctx_t * ctx,const char * iface,uint32_t mtu)82 net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface, uint32_t mtu)
83 {
84 struct argv argv = argv_new();
85
86 argv_printf(&argv, "%s link set dev %s up mtu %d", iproute_path, iface,
87 mtu);
88 argv_msg(M_INFO, &argv);
89 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed");
90
91 argv_free(&argv);
92
93 return 0;
94 }
95
96 int
net_addr_v4_add(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * addr,int prefixlen)97 net_addr_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
98 const in_addr_t *addr, int prefixlen)
99 {
100 struct argv argv = argv_new();
101
102 const char *addr_str = print_in_addr_t(*addr, 0, &ctx->gc);
103
104 argv_printf(&argv, "%s addr add dev %s %s/%d", iproute_path, iface,
105 addr_str, prefixlen);
106 argv_msg(M_INFO, &argv);
107 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
108
109 argv_free(&argv);
110
111 return 0;
112 }
113
114 int
net_addr_v6_add(openvpn_net_ctx_t * ctx,const char * iface,const struct in6_addr * addr,int prefixlen)115 net_addr_v6_add(openvpn_net_ctx_t *ctx, const char *iface,
116 const struct in6_addr *addr, int prefixlen)
117 {
118 struct argv argv = argv_new();
119 char *addr_str = (char *)print_in6_addr(*addr, 0, &ctx->gc);
120
121 argv_printf(&argv, "%s -6 addr add %s/%d dev %s", iproute_path, addr_str,
122 prefixlen, iface);
123 argv_msg(M_INFO, &argv);
124 openvpn_execve_check(&argv, ctx->es, S_FATAL,
125 "Linux ip -6 addr add failed");
126
127 argv_free(&argv);
128
129 return 0;
130 }
131
132 int
net_addr_v4_del(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * addr,int prefixlen)133 net_addr_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
134 const in_addr_t *addr, int prefixlen)
135 {
136 struct argv argv = argv_new();
137 const char *addr_str = print_in_addr_t(*addr, 0, &ctx->gc);
138
139 argv_printf(&argv, "%s addr del dev %s %s/%d", iproute_path, iface,
140 addr_str, prefixlen);
141
142 argv_msg(M_INFO, &argv);
143 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
144
145 argv_free(&argv);
146
147 return 0;
148 }
149
150 int
net_addr_v6_del(openvpn_net_ctx_t * ctx,const char * iface,const struct in6_addr * addr,int prefixlen)151 net_addr_v6_del(openvpn_net_ctx_t *ctx, const char *iface,
152 const struct in6_addr *addr, int prefixlen)
153 {
154 struct argv argv = argv_new();
155 char *addr_str = (char *)print_in6_addr(*addr, 0, &ctx->gc);
156
157 argv_printf(&argv, "%s -6 addr del %s/%d dev %s", iproute_path,
158 addr_str, prefixlen, iface);
159 argv_msg(M_INFO, &argv);
160 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip -6 addr del failed");
161
162 argv_free(&argv);
163
164 return 0;
165 }
166
167 int
net_addr_ptp_v4_add(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * local,const in_addr_t * remote)168 net_addr_ptp_v4_add(openvpn_net_ctx_t *ctx, const char *iface,
169 const in_addr_t *local, const in_addr_t *remote)
170 {
171 struct argv argv = argv_new();
172 const char *local_str = print_in_addr_t(*local, 0, &ctx->gc);
173 const char *remote_str = print_in_addr_t(*remote, 0, &ctx->gc);
174
175 argv_printf(&argv, "%s addr add dev %s local %s peer %s", iproute_path,
176 iface, local_str, remote_str);
177 argv_msg(M_INFO, &argv);
178 openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip addr add failed");
179
180 argv_free(&argv);
181
182 return 0;
183 }
184
185 int
net_addr_ptp_v4_del(openvpn_net_ctx_t * ctx,const char * iface,const in_addr_t * local,const in_addr_t * remote)186 net_addr_ptp_v4_del(openvpn_net_ctx_t *ctx, const char *iface,
187 const in_addr_t *local, const in_addr_t *remote)
188 {
189 struct argv argv = argv_new();
190 const char *local_str = print_in_addr_t(*local, 0, &ctx->gc);
191 const char *remote_str = print_in_addr_t(*remote, 0, &ctx->gc);
192
193 argv_printf(&argv, "%s addr del dev %s local %s peer %s", iproute_path,
194 iface, local_str, remote_str);
195 argv_msg(M_INFO, &argv);
196 openvpn_execve_check(&argv, ctx->es, 0, "Linux ip addr del failed");
197
198 argv_free(&argv);
199
200 return 0;
201 }
202
203 int
net_route_v4_add(openvpn_net_ctx_t * ctx,const in_addr_t * dst,int prefixlen,const in_addr_t * gw,const char * iface,uint32_t table,int metric)204 net_route_v4_add(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
205 const in_addr_t *gw, const char *iface, uint32_t table,
206 int metric)
207 {
208 struct argv argv = argv_new();
209 const char *dst_str = print_in_addr_t(*dst, 0, &ctx->gc);
210
211 argv_printf(&argv, "%s route add %s/%d", iproute_path, dst_str, prefixlen);
212
213 if (metric > 0)
214 {
215 argv_printf_cat(&argv, "metric %d", metric);
216 }
217
218 if (iface)
219 {
220 argv_printf_cat(&argv, "dev %s", iface);
221 }
222
223 if (gw)
224 {
225 const char *gw_str = print_in_addr_t(*gw, 0, &ctx->gc);
226
227 argv_printf_cat(&argv, "via %s", gw_str);
228 }
229
230 argv_msg(D_ROUTE, &argv);
231 openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route add command failed");
232
233 argv_free(&argv);
234
235 return 0;
236 }
237
238 int
net_route_v6_add(openvpn_net_ctx_t * ctx,const struct in6_addr * dst,int prefixlen,const struct in6_addr * gw,const char * iface,uint32_t table,int metric)239 net_route_v6_add(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
240 int prefixlen, const struct in6_addr *gw, const char *iface,
241 uint32_t table, int metric)
242 {
243 struct argv argv = argv_new();
244 char *dst_str = (char *)print_in6_addr(*dst, 0, &ctx->gc);
245
246 argv_printf(&argv, "%s -6 route add %s/%d dev %s", iproute_path, dst_str,
247 prefixlen, iface);
248
249 if (gw)
250 {
251 char *gw_str = (char *)print_in6_addr(*gw, 0, &ctx->gc);
252
253 argv_printf_cat(&argv, "via %s", gw_str);
254 }
255
256 if (metric > 0)
257 {
258 argv_printf_cat(&argv, "metric %d", metric);
259 }
260
261 argv_msg(D_ROUTE, &argv);
262 openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 add command failed");
263
264 argv_free(&argv);
265
266 return 0;
267 }
268
269 int
net_route_v4_del(openvpn_net_ctx_t * ctx,const in_addr_t * dst,int prefixlen,const in_addr_t * gw,const char * iface,uint32_t table,int metric)270 net_route_v4_del(openvpn_net_ctx_t *ctx, const in_addr_t *dst, int prefixlen,
271 const in_addr_t *gw, const char *iface, uint32_t table,
272 int metric)
273 {
274 struct argv argv = argv_new();
275 const char *dst_str = print_in_addr_t(*dst, 0, &ctx->gc);
276
277 argv_printf(&argv, "%s route del %s/%d", iproute_path, dst_str, prefixlen);
278
279 if (metric > 0)
280 {
281 argv_printf_cat(&argv, "metric %d", metric);
282 }
283
284 argv_msg(D_ROUTE, &argv);
285 openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route delete command failed");
286
287 argv_free(&argv);
288
289 return 0;
290 }
291
292 int
net_route_v6_del(openvpn_net_ctx_t * ctx,const struct in6_addr * dst,int prefixlen,const struct in6_addr * gw,const char * iface,uint32_t table,int metric)293 net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
294 int prefixlen, const struct in6_addr *gw, const char *iface,
295 uint32_t table, int metric)
296 {
297 struct argv argv = argv_new();
298 char *dst_str = (char *)print_in6_addr(*dst, 0, &ctx->gc);
299
300 argv_printf(&argv, "%s -6 route del %s/%d dev %s", iproute_path, dst_str,
301 prefixlen, iface);
302
303 if (gw)
304 {
305 char *gw_str = (char *)print_in6_addr(*gw, 0, &ctx->gc);
306
307 argv_printf_cat(&argv, "via %s", gw_str);
308 }
309
310 if (metric > 0)
311 {
312 argv_printf_cat(&argv, "metric %d", metric);
313 }
314
315 argv_msg(D_ROUTE, &argv);
316 openvpn_execve_check(&argv, ctx->es, 0, "ERROR: Linux route -6 del command failed");
317
318 argv_free(&argv);
319
320 return 0;
321 }
322
323 int
net_route_v4_best_gw(openvpn_net_ctx_t * ctx,const in_addr_t * dst,in_addr_t * best_gw,char * best_iface)324 net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
325 in_addr_t *best_gw, char *best_iface)
326 {
327 best_iface[0] = '\0';
328
329 FILE *fp = fopen("/proc/net/route", "r");
330 if (!fp)
331 {
332 return -1;
333 }
334
335 char line[256];
336 int count = 0;
337 unsigned int lowest_metric = UINT_MAX;
338 while (fgets(line, sizeof(line), fp) != NULL)
339 {
340 if (count)
341 {
342 unsigned int net_x = 0;
343 unsigned int mask_x = 0;
344 unsigned int gw_x = 0;
345 unsigned int metric = 0;
346 unsigned int flags = 0;
347 char name[16];
348 name[0] = '\0';
349
350 const int np = sscanf(line, "%15s\t%x\t%x\t%x\t%*s\t%*s\t%d\t%x",
351 name, &net_x, &gw_x, &flags, &metric,
352 &mask_x);
353
354 if (np == 6 && (flags & IFF_UP))
355 {
356 const in_addr_t net = ntohl(net_x);
357 const in_addr_t mask = ntohl(mask_x);
358 const in_addr_t gw = ntohl(gw_x);
359
360 if (!net && !mask && metric < lowest_metric)
361 {
362 *best_gw = gw;
363 strcpy(best_iface, name);
364 lowest_metric = metric;
365 }
366 }
367 }
368 ++count;
369 }
370 fclose(fp);
371
372 return 0;
373 }
374
375 /*
376 * The following function is not implemented in the iproute backend as it
377 * uses the sitnl implementation from networking_sitnl.c.
378 *
379 * int
380 * net_route_v6_best_gw(const struct in6_addr *dst,
381 * struct in6_addr *best_gw, char *best_iface)
382 */
383
384 #endif /* ENABLE_IPROUTE && TARGET_LINUX */
385