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