ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/conf.C
(Generate patch)

Comparing gvpe/src/conf.C (file contents):
Revision 1.54 by root, Tue Feb 15 13:31:23 2011 UTC vs.
Revision 1.65 by root, Fri Oct 11 07:56:07 2013 UTC

1/* 1/*
2 conf.c -- configuration code 2 conf.C -- configuration code
3 Copyright (C) 2003-2008 Marc Lehmann <gvpe@schmorp.de> 3 Copyright (C) 2003-2008,2011 Marc Lehmann <gvpe@schmorp.de>
4 4
5 This file is part of GVPE. 5 This file is part of GVPE.
6 6
7 GVPE is free software; you can redistribute it and/or modify it 7 GVPE is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the 8 under the terms of the GNU General Public License as published by the
38#include <errno.h> 38#include <errno.h>
39#include <netdb.h> 39#include <netdb.h>
40#include <sys/stat.h> 40#include <sys/stat.h>
41#include <sys/types.h> 41#include <sys/types.h>
42#include <unistd.h> 42#include <unistd.h>
43#include <pwd.h>
43 44
44#include "netcompat.h" 45#include "netcompat.h"
45 46
46#include <openssl/err.h> 47#include <openssl/err.h>
47#include <openssl/pem.h> 48#include <openssl/pem.h>
151 default_node.if_up_data = strdup (""); 152 default_node.if_up_data = strdup ("");
152 153
153#if ENABLE_DNS 154#if ENABLE_DNS
154 default_node.dns_port = 0; // default is 0 == client 155 default_node.dns_port = 0; // default is 0 == client
155 156
157 dns_case_preserving = true;
156 dns_forw_host = strdup ("127.0.0.1"); 158 dns_forw_host = strdup ("127.0.0.1");
157 dns_forw_port = 53; 159 dns_forw_port = 53;
158 dns_timeout_factor = DEFAULT_DNS_TIMEOUT_FACTOR; 160 dns_timeout_factor = DEFAULT_DNS_TIMEOUT_FACTOR;
159 dns_send_interval = DEFAULT_DNS_SEND_INTERVAL; 161 dns_send_interval = DEFAULT_DNS_SEND_INTERVAL;
160 dns_overlap_factor = DEFAULT_DNS_OVERLAP_FACTOR; 162 dns_overlap_factor = DEFAULT_DNS_OVERLAP_FACTOR;
161 dns_max_outstanding = DEFAULT_DNS_MAX_OUTSTANDING; 163 dns_max_outstanding = DEFAULT_DNS_MAX_OUTSTANDING;
162#endif 164#endif
163 165
164 conf.pidfilename = strdup (LOCALSTATEDIR "/run/gvpe.pid"); 166 pidfilename = strdup (LOCALSTATEDIR "/run/gvpe.pid");
167 seed_dev = strdup ("/dev/urandom");
168 reseed = DEFAULT_RESEED;
165} 169}
166 170
167void 171void
168configuration::cleanup () 172configuration::cleanup ()
169{ 173{
170 if (rsa_key) 174 if (rsa_key)
171 RSA_free (rsa_key); 175 RSA_free (rsa_key);
172 176
173 rsa_key = 0; 177 rsa_key = 0;
174 178
179 free (seed_dev); seed_dev = 0;
175 free (pidfilename); pidfilename = 0; 180 free (pidfilename); pidfilename = 0;
176 free (ifname); ifname = 0; 181 free (ifname); ifname = 0;
177#if ENABLE_HTTP_PROXY 182#if ENABLE_HTTP_PROXY
178 free (proxy_host); proxy_host = 0; 183 free (proxy_host); proxy_host = 0;
179 free (proxy_auth); proxy_auth = 0; 184 free (proxy_auth); proxy_auth = 0;
180#endif 185#endif
181#if ENABLE_DNS 186#if ENABLE_DNS
182 free (dns_forw_host); dns_forw_host = 0; 187 free (dns_forw_host); dns_forw_host = 0;
183#endif 188#endif
189 free (change_root); change_root = 0;
184 free (script_if_up); script_if_up = 0; 190 free (script_if_up); script_if_up = 0;
185 free (script_node_up); script_node_up = 0; 191 free (script_node_up); script_node_up = 0;
186 free (script_node_change); script_node_change = 0; 192 free (script_node_change); script_node_change = 0;
187 free (script_node_down); script_node_down = 0; 193 free (script_node_down); script_node_down = 0;
188} 194}
196 nodes.clear (); 202 nodes.clear ();
197 203
198 cleanup (); 204 cleanup ();
199 init (); 205 init ();
200} 206}
207
208conf_node *
209configuration::find_node (const char *name)
210{
211 for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i)
212 if (!strcmp ((*i)->nodename, name))
213 return *i;
214
215 return 0;
216}
217
218//static bool
219//is_true (const char *name)
220//{
221 //re
222//}
201 223
202#define parse_bool(target,name,trueval,falseval) do { \ 224#define parse_bool(target,name,trueval,falseval) do { \
203 if (!strcmp (val, "yes")) target = trueval; \ 225 if (!strcmp (val, "yes")) target = trueval; \
204 else if (!strcmp (val, "no")) target = falseval; \ 226 else if (!strcmp (val, "no")) target = falseval; \
205 else if (!strcmp (val, "true")) target = trueval; \ 227 else if (!strcmp (val, "true")) target = trueval; \
206 else if (!strcmp (val, "false")) target = falseval; \ 228 else if (!strcmp (val, "false")) target = falseval; \
207 else if (!strcmp (val, "on")) target = trueval; \ 229 else if (!strcmp (val, "on")) target = trueval; \
208 else if (!strcmp (val, "off")) target = falseval; \ 230 else if (!strcmp (val, "off")) target = falseval; \
209 else \ 231 else \
210 return _("illegal boolean value, only 'yes|true|on' or 'no|false|off' allowed. (ignored)"); \ 232 return _("illegal boolean value, only 'yes|true|on' or 'no|false|off' allowed, ignored"); \
211} while (0) 233} while (0)
212 234
213const char * 235const char *
214configuration_parser::parse_line (char *line) 236configuration_parser::parse_line (char *line)
215{ 237{
230 return 0; /* no tokens on this line */ 252 return 0; /* no tokens on this line */
231 253
232 if (var[0] == '#') 254 if (var[0] == '#')
233 return 0; /* comment: ignore */ 255 return 0; /* comment: ignore */
234 256
257 if (!strcmp (var, "global"))
258 {
259 node = &conf.default_node;
260 return 0;
261 }
262
235 char *val = strtok (NULL, "\t\n\r ="); 263 char *val = strtok (NULL, "\t\n\r =");
236 264
237 if (!val || val[0] == '#') 265 if (!val || val[0] == '#')
238 return _("no value given for variable. (ignored)"); 266 return _("no value given for variable, ignored");
239 267
240 if (!strcmp (var, "on")) 268 else if (!strcmp (var, "on"))
241 { 269 {
242 if (!::thisnode 270 if (::thisnode
243 || (val[0] == '!' && strcmp (val + 1, ::thisnode)) 271 && ((val[0] == '!' && strcmp (val + 1, ::thisnode))
244 || !strcmp (val, ::thisnode)) 272 || !strcmp (val, ::thisnode)))
245 return parse_line (strtok (NULL, "\n\r")); 273 return parse_line (strtok (NULL, "\n\r"));
246 else 274 }
247 return 0; 275
276 else if (!strcmp (var, "include"))
277 {
278 char *fname = conf.config_filename (val);
279 parse_file (fname);
280 free (fname);
248 } 281 }
249 282
250 // truly global 283 // truly global
251 if (!strcmp (var, "loglevel")) 284 else if (!strcmp (var, "loglevel"))
252 { 285 {
253 loglevel l = string_to_loglevel (val); 286 loglevel l = string_to_loglevel (val);
254 287
255 if (l == L_NONE) 288 if (l == L_NONE)
256 return _("unknown loglevel. (skipping)"); 289 return _("unknown loglevel, ignored");
257 } 290 }
291 else if (!strcmp (var, "serial"))
292 strncpy (conf.serial, val, sizeof (conf.serial));
258 else if (!strcmp (var, "ip-proto")) 293 else if (!strcmp (var, "ip-proto"))
259 conf.ip_proto = atoi (val); 294 conf.ip_proto = atoi (val);
260 else if (!strcmp (var, "icmp-type")) 295 else if (!strcmp (var, "icmp-type"))
261 { 296 {
262#if ENABLE_ICMP 297#if ENABLE_ICMP
263 conf.icmp_type = atoi (val); 298 conf.icmp_type = atoi (val);
264#endif 299#endif
265 } 300 }
301 else if (!strcmp (var, "chuser"))
302 {
303 struct passwd *pw = getpwnam (val);
304 if (!pw)
305 return _("user specified for chuser not found");
266 306
267 // per config 307 conf.change_uid = pw->pw_uid;
308 conf.change_gid = pw->pw_gid;
309 }
310 else if (!strcmp (var, "chuid"))
311 conf.change_uid = atoi (val);
312 else if (!strcmp (var, "chgid"))
313 conf.change_gid = atoi (val);
314 else if (!strcmp (var, "chroot"))
315 free (conf.change_root), conf.change_root = strdup (val);
316
317 // per node
268 else if (!strcmp (var, "node")) 318 else if (!strcmp (var, "node"))
269 { 319 {
270 parse_argv (); 320 node = conf.find_node (val);
271 321
322 if (!node)
323 {
272 conf.default_node.id++; 324 conf.default_node.id++;
273 node = new conf_node (conf.default_node); 325 node = new conf_node (conf.default_node);
274 conf.nodes.push_back (node); 326 conf.nodes.push_back (node);
275 node->nodename = strdup (val); 327 node->nodename = strdup (val);
276
277 {
278 char *fname;
279 FILE *f;
280
281 asprintf (&fname, "%s/pubkey/%s", confbase, node->nodename);
282
283 f = fopen (fname, "r");
284 if (f)
285 {
286 node->rsa_key = RSA_new ();
287
288 if (!PEM_read_RSAPublicKey(f, &node->rsa_key, NULL, NULL))
289 {
290 ERR_load_RSA_strings (); ERR_load_PEM_strings ();
291 slog (L_ERR, _("unable to open public rsa key file '%s': %s"), fname, ERR_error_string (ERR_get_error (), 0));
292 exit (EXIT_FAILURE);
293 }
294
295 require (RSA_blinding_on (node->rsa_key, 0));
296
297 fclose (f);
298 } 328 }
299 else
300 {
301 slog (need_keys ? L_ERR : L_NOTICE, _("unable to read public rsa key file '%s': %s"), fname, strerror (errno));
302
303 if (need_keys)
304 exit (EXIT_FAILURE);
305 }
306
307 free (fname);
308 }
309
310 if (::thisnode && !strcmp (node->nodename, ::thisnode))
311 conf.thisnode = node;
312 } 329 }
313 else if (!strcmp (var, "private-key")) 330 else if (!strcmp (var, "private-key"))
314 free (conf.prikeyfile), conf.prikeyfile = strdup (val); 331 free (conf.prikeyfile), conf.prikeyfile = strdup (val);
315 else if (!strcmp (var, "ifpersist")) 332 else if (!strcmp (var, "ifpersist"))
316 parse_bool (conf.ifpersist, "ifpersist", true, false); 333 parse_bool (conf.ifpersist, "ifpersist", true, false);
322 conf.keepalive = atoi (val); 339 conf.keepalive = atoi (val);
323 else if (!strcmp (var, "mtu")) 340 else if (!strcmp (var, "mtu"))
324 conf.mtu = atoi (val); 341 conf.mtu = atoi (val);
325 else if (!strcmp (var, "nfmark")) 342 else if (!strcmp (var, "nfmark"))
326 conf.nfmark = atoi (val); 343 conf.nfmark = atoi (val);
344 else if (!strcmp (var, "seed-device"))
345 free (conf.seed_dev), conf.seed_dev = strdup (val);
346 else if (!strcmp (var, "seed-interval"))
347 conf.reseed = atoi (val);
327 else if (!strcmp (var, "if-up")) 348 else if (!strcmp (var, "if-up"))
328 free (conf.script_if_up), conf.script_if_up = strdup (val); 349 free (conf.script_if_up), conf.script_if_up = strdup (val);
329 else if (!strcmp (var, "node-up")) 350 else if (!strcmp (var, "node-up"))
330 free (conf.script_node_up), conf.script_node_up = strdup (val); 351 free (conf.script_node_up), conf.script_node_up = strdup (val);
331 else if (!strcmp (var, "node-change")) 352 else if (!strcmp (var, "node-change"))
368 { 389 {
369#if ENABLE_DNS 390#if ENABLE_DNS
370 conf.dns_max_outstanding = atoi (val); 391 conf.dns_max_outstanding = atoi (val);
371#endif 392#endif
372 } 393 }
394 else if (!strcmp (var, "dns-case-preserving"))
395 {
396#if ENABLE_DNS
397 parse_bool (conf.dns_case_preserving, "dns-case-preserving", true, false);
398#endif
399 }
373 else if (!strcmp (var, "http-proxy-host")) 400 else if (!strcmp (var, "http-proxy-host"))
374 { 401 {
375#if ENABLE_HTTP_PROXY 402#if ENABLE_HTTP_PROXY
376 free (conf.proxy_host), conf.proxy_host = strdup (val); 403 free (conf.proxy_host), conf.proxy_host = strdup (val);
377#endif 404#endif
431 else if (!strcmp (val, "always")) 458 else if (!strcmp (val, "always"))
432 node->connectmode = conf_node::C_ALWAYS; 459 node->connectmode = conf_node::C_ALWAYS;
433 else if (!strcmp (val, "disabled")) 460 else if (!strcmp (val, "disabled"))
434 node->connectmode = conf_node::C_DISABLED; 461 node->connectmode = conf_node::C_DISABLED;
435 else 462 else
436 return _("illegal value for 'connectmode', use one of 'ondemand', 'never', 'always' or 'disabled'. (ignored)"); 463 return _("illegal value for 'connectmode', use one of 'ondemand', 'never', 'always' or 'disabled', ignored");
437 } 464 }
438 else if (!strcmp (var, "inherit-tos")) 465 else if (!strcmp (var, "inherit-tos"))
439 parse_bool (node->inherit_tos, "inherit-tos", true, false); 466 parse_bool (node->inherit_tos, "inherit-tos", true, false);
440 else if (!strcmp (var, "compress")) 467 else if (!strcmp (var, "compress"))
441 parse_bool (node->compress, "compress", true, false); 468 parse_bool (node->compress, "compress", true, false);
469 else if (!strcmp (var, "low-power"))
470 parse_bool (node->low_power, "low-power", true, false);
442 // all these bool options really really cost a lot of executable size! 471 // all these bool options really really cost a lot of executable size!
443 else if (!strcmp (var, "enable-tcp")) 472 else if (!strcmp (var, "enable-tcp"))
444 { 473 {
445#if ENABLE_TCP 474#if ENABLE_TCP
446 u8 v; parse_bool (v, "enable-tcp" , PROT_TCPv4, 0); node->protocols = (node->protocols & ~PROT_TCPv4) | v; 475 u8 v; parse_bool (v, "enable-tcp" , PROT_TCPv4, 0); node->protocols = (node->protocols & ~PROT_TCPv4) | v;
475 else if (!strcmp (var, "max-queue")) 504 else if (!strcmp (var, "max-queue"))
476 node->max_queue = atoi (val); 505 node->max_queue = atoi (val);
477 506
478 // unknown or misplaced 507 // unknown or misplaced
479 else 508 else
480 return _("unknown configuration directive. (ignored)"); 509 return _("unknown configuration directive - ignored");
481 510
482 return 0; 511 return 0;
483} 512}
484 513
485void 514void
497 connectmode = C_ALWAYS; 526 connectmode = C_ALWAYS;
498 } 527 }
499} 528}
500 529
501void 530void
502configuration_parser::parse_argv () 531configuration_parser::parse_file (const char *fname)
503{ 532{
504 for (int i = 0; i < argc; ++i) 533 if (FILE *f = fopen (fname, "r"))
505 { 534 {
506 char *v = argv [i]; 535 char line [2048];
536 int lineno = 0;
507 537
508 if (!*v) 538 while (fgets (line, sizeof (line), f))
509 continue;
510
511 char *enode = v;
512
513 while (*enode != '.' && *enode > ' ' && *enode != '=' && *enode)
514 enode++;
515
516 if (*enode != '.')
517 enode = 0;
518
519 char *wnode = node == &conf.default_node
520 ? 0
521 : node->nodename;
522
523 if ((!wnode && !enode)
524 || (wnode && enode && !strncmp (wnode, v, enode - v)))
525 { 539 {
540 lineno++;
541
526 const char *warn = parse_line (enode ? enode + 1 : v); 542 const char *warn = parse_line (line);
527 543
528 if (warn) 544 if (warn)
529 slog (L_WARN, _("%s, while parsing command line option '%s'."), warn, v); 545 slog (L_WARN, _("%s, at '%s', line %d."), warn, fname, lineno);
530
531 *v = 0;
532 } 546 }
547
548 fclose (f);
549 }
550 else
551 {
552 slog (L_ERR, _("unable to read config file '%s': %s"), fname, strerror (errno));
553 exit (EXIT_FAILURE);
533 } 554 }
534} 555}
535 556
536configuration_parser::configuration_parser (configuration &conf, 557configuration_parser::configuration_parser (configuration &conf,
537 bool need_keys, 558 bool need_keys,
538 int argc, 559 int argc,
539 char **argv) 560 char **argv)
540: conf (conf),need_keys (need_keys), argc (argc), argv (argv) 561: conf (conf), need_keys (need_keys), argc (argc), argv (argv)
541{ 562{
542 char *fname; 563 char *fname;
543 FILE *f;
544 564
545 conf.clear (); 565 conf.clear ();
566 node = &conf.default_node;
546 567
547 asprintf (&fname, "%s/gvpe.conf", confbase); 568 asprintf (&fname, "%s/gvpe.conf", confbase);
548 f = fopen (fname, "r"); 569 parse_file (fname);
549
550 if (f)
551 {
552 char line[16384];
553 int lineno = 0;
554 node = &conf.default_node;
555
556 while (fgets (line, sizeof (line), f))
557 {
558 lineno++;
559
560 const char *warn = parse_line (line);
561
562 if (warn)
563 slog (L_WARN, _("%s, at '%s', line %d."), warn, fname, lineno);
564 }
565
566 fclose (f);
567
568 parse_argv ();
569 }
570 else
571 {
572 slog (L_ERR, _("unable to read config file '%s': %s"), fname, strerror (errno));
573 exit (EXIT_FAILURE);
574 }
575
576 free (fname); 570 free (fname);
577 571
578 fname = conf.config_filename (conf.prikeyfile, "hostkey"); 572 fname = conf.config_filename (conf.prikeyfile, "hostkey");
579 573
580 f = fopen (fname, "r"); 574 if (FILE *f = fopen (fname, "r"))
581 if (f)
582 { 575 {
583 conf.rsa_key = RSA_new (); 576 conf.rsa_key = RSA_new ();
584 577
585 if (!PEM_read_RSAPrivateKey (f, &conf.rsa_key, NULL, NULL)) 578 if (!PEM_read_RSAPrivateKey (f, &conf.rsa_key, NULL, NULL))
586 { 579 {
593 586
594 fclose (f); 587 fclose (f);
595 } 588 }
596 else 589 else
597 { 590 {
598 slog (need_keys ? L_ERR : L_NOTICE, _("unable to open private rsa key file '%s': %s"), fname, strerror (errno));
599
600 if (need_keys) 591 if (need_keys)
592 {
593 slog (need_keys ? L_ERR : L_NOTICE, _("unable to open private rsa key file '%s': %s"), fname, strerror (errno));
601 exit (EXIT_FAILURE); 594 exit (EXIT_FAILURE);
602 }
603
604 if (need_keys && ::thisnode
605 && conf.rsa_key && conf.thisnode && conf.thisnode->rsa_key)
606 if (BN_cmp (conf.rsa_key->n, conf.thisnode->rsa_key->n) != 0
607 || BN_cmp (conf.rsa_key->e, conf.thisnode->rsa_key->e) != 0)
608 {
609 slog (L_NOTICE, _("private hostkey and public node key mismatch: is '%s' the correct node?"), ::thisnode);
610 exit (EXIT_FAILURE);
611 } 595 }
596 }
612 597
613 free (fname); 598 free (fname);
614 599
600 fname = conf.config_filename (conf.pidfilename);
601 free (conf.pidfilename); conf.pidfilename = fname;
602
615 for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i) 603 for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i)
604 {
605 conf_node *node = *i;
606 char *fname;
607 FILE *f;
608
609 asprintf (&fname, "%s/pubkey/%s", confbase, node->nodename);
610
611 f = fopen (fname, "r");
612 if (f)
613 {
614 node->rsa_key = RSA_new ();
615
616 if (!PEM_read_RSAPublicKey (f, &node->rsa_key, NULL, NULL))
617 {
618 ERR_load_RSA_strings (); ERR_load_PEM_strings ();
619 slog (L_ERR, _("unable to open public rsa key file '%s': %s"), fname, ERR_error_string (ERR_get_error (), 0));
620 exit (EXIT_FAILURE);
621 }
622
623 require (RSA_blinding_on (node->rsa_key, 0));
624
625 fclose (f);
626 }
627 else
628 {
629 slog (need_keys ? L_ERR : L_NOTICE, _("unable to read public rsa key file '%s': %s"), fname, strerror (errno));
630
631 if (need_keys)
632 exit (EXIT_FAILURE);
633 }
634
635 free (fname);
636
616 (*i)->finalise (); 637 (*i)->finalise ();
638 }
639
640 if (::thisnode)
641 {
642 conf.thisnode = conf.find_node (::thisnode);
643
644 if (need_keys)
645 {
646 if (!conf.thisnode)
647 {
648 slog (L_NOTICE, _("local node ('%s') not found in config file, aborting."), ::thisnode);
649 exit (EXIT_FAILURE);
650 }
651
652 if (conf.rsa_key && conf.thisnode->rsa_key)
653 if (BN_cmp (conf.rsa_key->n, conf.thisnode->rsa_key->n) != 0
654 || BN_cmp (conf.rsa_key->e, conf.thisnode->rsa_key->e) != 0)
655 {
656 slog (L_NOTICE, _("private hostkey and public node key mismatch: is '%s' the correct node?"), ::thisnode);
657 exit (EXIT_FAILURE);
658 }
659 }
660 }
661
662 parse_argv ();
663}
664
665void
666configuration_parser::parse_argv ()
667{
668 for (int i = 0; i < argc; ++i)
669 {
670 char *v = argv [i];
671
672 if (!*v)
673 continue;
674
675 char *enode = v;
676
677 while (*enode != '.' && *enode > ' ' && *enode != '=' && *enode)
678 enode++;
679
680 if (*enode != '.')
681 enode = 0;
682
683 if (enode)
684 {
685 char *val = strdup (v);
686 val [enode - v] = 0;
687 node = conf.find_node (val);
688 free (val);
689
690 if (!node)
691 {
692 slog (L_WARN, _("command line option '%s' refers to unknown node, ignoring."), v);
693 continue;
694 }
695 }
696 else
697 node = &conf.default_node;
698
699 const char *warn = parse_line (enode ? enode + 1 : v);
700
701 if (warn)
702 slog (L_WARN, _("%s, while parsing command line option '%s'."), warn, v);
703 }
617} 704}
618 705
619char * 706char *
620configuration::config_filename (const char *name, const char *dflt) 707configuration::config_filename (const char *name, const char *dflt)
621{ 708{
622 char *fname; 709 char *fname;
623 710
624 asprintf (&fname, name ? name : dflt, ::thisnode); 711 asprintf (&fname, name ? name : dflt, ::thisnode ? ::thisnode : "<unset>");
625 712
626 if (!ABSOLUTE_PATH (fname)) 713 if (!ABSOLUTE_PATH (fname))
627 { 714 {
628 char *rname = fname; 715 char *rname = fname;
629 asprintf (&fname, "%s/%s", confbase, rname); 716 asprintf (&fname, "%s/%s", confbase, rname);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines