1 /*
2 * Copyright (c) 2015, Laurent COUSTET <ed@zehome.com>
3 *
4 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "includes.h"
27 #include "mlvpn.h"
28 #include "configlib.h"
29 #include "tool.h"
30 #include "crypto.h"
31 #include "tuntap_generic.h"
32
33 extern char *status_command;
34 extern struct mlvpn_options_s mlvpn_options;
35 extern struct mlvpn_filters_s mlvpn_filters;
36 extern struct tuntap_s tuntap;
37 extern struct mlvpn_reorder_buffer *reorder_buffer;
38
39 /* Config file reading / re-read.
40 * config_file_fd: fd opened in priv_open_config
41 * first_time: set to 0 for re-read, or 1 for initial configuration
42 */
43 int
mlvpn_config(int config_file_fd,int first_time)44 mlvpn_config(int config_file_fd, int first_time)
45 {
46 config_t *config, *work;
47 mlvpn_tunnel_t *tmptun;
48 char *tmp = NULL;
49 char *mode = NULL;
50 char *lastSection = NULL;
51 char *tundevname = NULL;
52 char *password = NULL;
53 uint32_t tun_mtu = 0;
54
55 uint32_t default_loss_tolerence = 100;
56 uint32_t default_timeout = 60;
57 uint32_t default_server_mode = 0; /* 0 => client */
58 uint32_t cleartext_data = 0;
59 uint32_t fallback_only = 0;
60 uint32_t reorder_buffer_size = 0;
61
62 mlvpn_options.fallback_available = 0;
63
64 /* reset all bpf filters on every interface */
65 #ifdef HAVE_FILTERS
66 struct bpf_program filter;
67 pcap_t *pcap_dead_p = pcap_open_dead(DLT_RAW, DEFAULT_MTU);
68 memset(&mlvpn_filters, 0, sizeof(mlvpn_filters));
69 #endif
70
71 work = config = _conf_parseConfig(config_file_fd);
72 if (! config)
73 goto error;
74
75 while (work)
76 {
77 if ((work->section != NULL) && !mystr_eq(work->section, lastSection))
78 {
79 lastSection = work->section;
80 if (mystr_eq(lastSection, "general"))
81 {
82 /* Thoses settings can only by set at start time */
83 if (first_time)
84 {
85 _conf_set_str_from_conf(
86 config, lastSection, "statuscommand", &status_command, NULL,
87 NULL, 0);
88 _conf_set_str_from_conf(
89 config, lastSection, "interface_name", &tundevname, "mlvpn0",
90 NULL, 0);
91 if (tundevname) {
92 strlcpy(tuntap.devname, tundevname, sizeof(tuntap.devname));
93 free(tundevname);
94 }
95 _conf_set_str_from_conf(
96 config, lastSection, "tuntap", &tmp, "tun", NULL, 0);
97 if (tmp) {
98 if (mystr_eq(tmp, "tun"))
99 tuntap.type = MLVPN_TUNTAPMODE_TUN;
100 else
101 tuntap.type = MLVPN_TUNTAPMODE_TAP;
102 free(tmp);
103 }
104 /* Control configuration */
105 _conf_set_str_from_conf(
106 config, lastSection, "control_unix_path", &tmp, NULL,
107 NULL, 0);
108 if (tmp) {
109 strlcpy(mlvpn_options.control_unix_path, tmp,
110 sizeof(mlvpn_options.control_unix_path));
111 free(tmp);
112 }
113 _conf_set_str_from_conf(
114 config, lastSection, "control_bind_host", &tmp, NULL,
115 NULL, 0);
116 if (tmp) {
117 strlcpy(mlvpn_options.control_bind_host, tmp,
118 sizeof(mlvpn_options.control_bind_host));
119 free(tmp);
120 }
121 _conf_set_str_from_conf(
122 config, lastSection, "control_bind_port", &tmp, NULL,
123 NULL, 0);
124 if (tmp) {
125 strlcpy(mlvpn_options.control_bind_port, tmp,
126 sizeof(mlvpn_options.control_bind_port));
127 free(tmp);
128 }
129 }
130 /* This is important to be parsed every time because
131 * it's used later in the configuration parsing
132 */
133 _conf_set_str_from_conf(
134 config, lastSection, "mode", &mode, NULL,
135 "Operation mode is mandatory.", 1);
136 if (mystr_eq(mode, "server"))
137 default_server_mode = 1;
138 if (mode)
139 free(mode);
140
141 _conf_set_str_from_conf(
142 config, lastSection, "password", &password, NULL,
143 "Password is mandatory.", 2);
144 if (password) {
145 log_info("config", "new password set");
146 crypto_set_password(password, strlen(password));
147 memset(password, 0, strlen(password));
148 free(password);
149 }
150 _conf_set_uint_from_conf(
151 config, lastSection, "cleartext_data", &cleartext_data, 0,
152 NULL, 0);
153 mlvpn_options.cleartext_data = cleartext_data;
154
155
156 _conf_set_uint_from_conf(
157 config, lastSection, "timeout", &default_timeout, 60,
158 NULL, 0);
159 if (default_timeout < 5) {
160 log_warnx("config", "timeout capped to 5 seconds");
161 default_timeout = 5;
162 }
163
164 _conf_set_uint_from_conf(
165 config, lastSection, "reorder_buffer_size",
166 &reorder_buffer_size,
167 0, NULL, 0);
168 if (reorder_buffer_size != mlvpn_options.reorder_buffer_size) {
169 log_info("config",
170 "reorder_buffer_size changed from %d to %d",
171 mlvpn_options.reorder_buffer_size,
172 reorder_buffer_size);
173 if (reorder_buffer_size != 0 &&
174 mlvpn_options.reorder_buffer_size != 0) {
175 mlvpn_reorder_free(reorder_buffer);
176 reorder_buffer = NULL;
177 }
178 mlvpn_options.reorder_buffer_size = reorder_buffer_size;
179 if (mlvpn_options.reorder_buffer_size > 0) {
180 if (reorder_buffer) {
181 mlvpn_reorder_free(reorder_buffer);
182 }
183 reorder_buffer = mlvpn_reorder_create(
184 mlvpn_options.reorder_buffer_size);
185 if (reorder_buffer == NULL) {
186 fatal("config", "reorder_buffer allocation failed");
187 }
188 }
189 }
190
191 _conf_set_uint_from_conf(
192 config, lastSection, "loss_tolerence",
193 &default_loss_tolerence, 100, NULL, 0);
194 if (default_loss_tolerence > 100) {
195 log_warnx("config", "loss_tolerence is capped to 100 %%");
196 default_loss_tolerence = 100;
197 }
198
199 /* Tunnel configuration */
200 _conf_set_str_from_conf(
201 config, lastSection, "ip4", &tmp, NULL, NULL, 0);
202 if (tmp) {
203 strlcpy(mlvpn_options.ip4, tmp, sizeof(mlvpn_options.ip4));
204 free(tmp);
205 } else {
206 memset(mlvpn_options.ip4_gateway, 0,
207 sizeof(mlvpn_options.ip4_gateway));
208 }
209
210 _conf_set_str_from_conf(
211 config, lastSection, "ip6", &tmp, NULL, NULL, 0);
212 if (tmp) {
213 strlcpy(mlvpn_options.ip6, tmp, sizeof(mlvpn_options.ip6));
214 free(tmp);
215 } else {
216 memset(mlvpn_options.ip4_gateway, 0,
217 sizeof(mlvpn_options.ip4_gateway));
218 }
219
220 _conf_set_str_from_conf(
221 config, lastSection, "ip4_gateway", &tmp, NULL, NULL, 0);
222 if (tmp) {
223 strlcpy(mlvpn_options.ip4_gateway, tmp,
224 sizeof(mlvpn_options.ip4_gateway));
225 free(tmp);
226 } else {
227 memset(mlvpn_options.ip4_gateway, 0,
228 sizeof(mlvpn_options.ip4_gateway));
229 }
230
231 _conf_set_str_from_conf(
232 config, lastSection, "ip6_gateway", &tmp, NULL, NULL, 0);
233 if (tmp) {
234 strlcpy(mlvpn_options.ip6_gateway, tmp,
235 sizeof(mlvpn_options.ip6_gateway));
236 free(tmp);
237 } else {
238 memset(mlvpn_options.ip6_gateway, 0,
239 sizeof(mlvpn_options.ip6_gateway));
240 }
241
242 _conf_set_str_from_conf(
243 config, lastSection, "ip4_routes", &tmp, NULL, NULL, 0);
244 if (tmp) {
245 strlcpy(mlvpn_options.ip4_routes, tmp,
246 sizeof(mlvpn_options.ip4_routes));
247 free(tmp);
248 } else {
249 memset(mlvpn_options.ip4_routes, 0,
250 sizeof(mlvpn_options.ip4_routes));
251 }
252
253 _conf_set_str_from_conf(
254 config, lastSection, "ip6_routes", &tmp, NULL, NULL, 0);
255 if (tmp) {
256 strlcpy(mlvpn_options.ip6_routes, tmp,
257 sizeof(mlvpn_options.ip6_routes));
258 free(tmp);
259 } else {
260 memset(mlvpn_options.ip6_routes, 0,
261 sizeof(mlvpn_options.ip6_routes));
262 }
263
264 _conf_set_uint_from_conf(
265 config, lastSection, "mtu", &tun_mtu, 1432, NULL, 0);
266 if (tun_mtu != 0) {
267 mlvpn_options.mtu = tun_mtu;
268 }
269 } else if (strncmp(lastSection, "filters", 7) != 0) {
270 char *bindaddr;
271 char *bindport;
272 uint32_t bindfib = 0;
273 char *dstaddr;
274 char *dstport;
275 uint32_t bwlimit = 0;
276 uint32_t timeout = 30;
277 uint32_t loss_tolerence;
278 int create_tunnel = 1;
279
280 if (default_server_mode)
281 {
282 _conf_set_str_from_conf(
283 config, lastSection, "bindhost", &bindaddr, NULL,
284 NULL, 0);
285 _conf_set_str_from_conf(
286 config, lastSection, "bindport", &bindport, NULL,
287 "bind port is mandatory in server mode.\n", 1);
288 _conf_set_uint_from_conf(
289 config, lastSection, "bindfib", &bindfib, 0,
290 NULL, 0);
291 _conf_set_str_from_conf(
292 config, lastSection, "remotehost", &dstaddr, NULL,
293 NULL, 0);
294 _conf_set_str_from_conf(
295 config, lastSection, "remoteport", &dstport, NULL,
296 NULL, 0);
297 } else {
298 _conf_set_str_from_conf(
299 config, lastSection, "bindhost", &bindaddr, NULL,
300 NULL, 0);
301 _conf_set_str_from_conf(
302 config, lastSection, "bindport", &bindport, NULL,
303 NULL, 0);
304 _conf_set_uint_from_conf(
305 config, lastSection, "bindfib", &bindfib, 0,
306 NULL, 0);
307 _conf_set_str_from_conf(
308 config, lastSection, "remotehost", &dstaddr, NULL,
309 "No remote address specified.\n", 1);
310 _conf_set_str_from_conf(
311 config, lastSection, "remoteport", &dstport, NULL,
312 "No remote port specified.\n", 1);
313 }
314 _conf_set_uint_from_conf(
315 config, lastSection, "bandwidth_upload", &bwlimit, 0,
316 NULL, 0);
317 _conf_set_uint_from_conf(
318 config, lastSection, "timeout", &timeout, default_timeout,
319 NULL, 0);
320 if (timeout < 5) {
321 log_warnx("config", "timeout capped to 5 seconds");
322 timeout = 5;
323 }
324 _conf_set_uint_from_conf(
325 config, lastSection, "loss_tolerence", &loss_tolerence,
326 default_loss_tolerence, NULL, 0);
327 if (loss_tolerence > 100) {
328 log_warnx("config", "loss_tolerence is capped to 100 %%");
329 loss_tolerence = 100;
330 }
331 _conf_set_uint_from_conf(
332 config, lastSection, "fallback_only", &fallback_only, 0,
333 NULL, 0);
334 if (fallback_only) {
335 mlvpn_options.fallback_available = 1;
336 }
337 LIST_FOREACH(tmptun, &rtuns, entries)
338 {
339 if (mystr_eq(lastSection, tmptun->name))
340 {
341 log_info("config",
342 "%s restart for configuration reload",
343 tmptun->name);
344 if ((! mystr_eq(tmptun->bindaddr, bindaddr)) ||
345 (! mystr_eq(tmptun->bindport, bindport)) ||
346 (tmptun->bindfib != bindfib) ||
347 (! mystr_eq(tmptun->destaddr, dstaddr)) ||
348 (! mystr_eq(tmptun->destport, dstport))) {
349 mlvpn_rtun_status_down(tmptun);
350 }
351
352 if (bindaddr) {
353 strlcpy(tmptun->bindaddr, bindaddr, sizeof(tmptun->bindaddr));
354 }
355 if (bindport) {
356 strlcpy(tmptun->bindport, bindport, sizeof(tmptun->bindport));
357 }
358 if (tmptun->bindfib != bindfib) {
359 tmptun->bindfib = bindfib;
360 }
361 if (dstaddr) {
362 strlcpy(tmptun->destaddr, dstaddr, sizeof(tmptun->destaddr));
363 }
364 if (dstport) {
365 strlcpy(tmptun->destport, dstport, sizeof(tmptun->destport));
366 }
367 if (tmptun->fallback_only != fallback_only)
368 {
369 log_info("config", "%s fallback_only changed from %d to %d",
370 tmptun->name, tmptun->fallback_only, fallback_only);
371 tmptun->fallback_only = fallback_only;
372 }
373 if (tmptun->bandwidth != bwlimit)
374 {
375 log_info("config", "%s bandwidth changed from %d to %d",
376 tmptun->name, tmptun->bandwidth, bwlimit);
377 tmptun->bandwidth = bwlimit;
378 }
379 if (tmptun->loss_tolerence != loss_tolerence)
380 {
381 log_info("config", "%s loss tolerence changed from %d%% to %d%%",
382 tmptun->name, tmptun->loss_tolerence, loss_tolerence);
383 tmptun->loss_tolerence = loss_tolerence;
384 }
385 create_tunnel = 0;
386 break; /* Very important ! */
387 }
388 }
389
390 if (create_tunnel)
391 {
392 log_info("config", "%s tunnel added", lastSection);
393 mlvpn_rtun_new(
394 lastSection, bindaddr, bindport, bindfib, dstaddr, dstport,
395 default_server_mode, timeout, fallback_only,
396 bwlimit, loss_tolerence);
397 }
398 if (bindaddr)
399 free(bindaddr);
400 if (bindport)
401 free(bindport);
402 if (dstaddr)
403 free(dstaddr);
404 if (dstport)
405 free(dstport);
406 }
407 } else if (lastSection == NULL)
408 lastSection = work->section;
409 work = work->next;
410 }
411
412 /* Ok, let's delete old tunnels */
413 if (! first_time)
414 {
415 LIST_FOREACH(tmptun, &rtuns, entries)
416 {
417 int found_in_config = 0;
418
419 work = config;
420 while (work)
421 {
422 if (work->conf && work->section &&
423 mystr_eq(work->section, tmptun->name))
424 {
425 found_in_config = 1;
426 break;
427 }
428 work = work->next;
429 }
430
431 if (! found_in_config)
432 {
433 log_info("config", "%s tunnel removed", tmptun->name);
434 mlvpn_rtun_drop(tmptun);
435 }
436 }
437 }
438
439 #ifdef HAVE_FILTERS
440 work = config;
441 int found_in_config = 0;
442 while (work)
443 {
444 if (strncmp(work->section, "filters", 7) == 0) {
445 memset(&filter, 0, sizeof(filter));
446 if (pcap_compile(pcap_dead_p, &filter, work->conf->val,
447 1, PCAP_NETMASK_UNKNOWN) != 0) {
448 log_warnx("config", "invalid filter %s = %s: %s",
449 work->conf->var, work->conf->val, pcap_geterr(pcap_dead_p));
450 } else {
451 found_in_config = 0;
452 LIST_FOREACH(tmptun, &rtuns, entries) {
453 if (strcmp(work->conf->var, tmptun->name) == 0) {
454 if (mlvpn_filters_add(&filter, tmptun) != 0) {
455 log_warnx("config", "%s filter %s error: too many filters",
456 tmptun->name, work->conf->val);
457 } else {
458 log_debug("config", "%s added filter: %s",
459 tmptun->name, work->conf->val);
460 found_in_config = 1;
461 break;
462 }
463 }
464 }
465 if (!found_in_config) {
466 log_warnx("config", "(filters) %s interface not found",
467 work->conf->var);
468 }
469 }
470 }
471 work = work->next;
472 }
473 #endif
474
475 //_conf_printConfig(config);
476 _conf_freeConfig(config);
477 #ifdef HAVE_FILTERS
478 pcap_close(pcap_dead_p);
479 #endif
480
481 if (first_time && status_command)
482 priv_init_script(status_command);
483 return 0;
484 error:
485 log_warnx("config", "parse error");
486 return 1;
487 }
488