ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/conf.C
Revision: 1.57
Committed: Sat Dec 17 22:05:34 2011 UTC (12 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.56: +19 -0 lines
Log Message:
ipv42_hack

File Contents

# Content
1 /*
2 conf.C -- configuration code
3 Copyright (C) 2003-2008,2011 Marc Lehmann <gvpe@schmorp.de>
4
5 This file is part of GVPE.
6
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
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, see <http://www.gnu.org/licenses/>.
19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this Program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a modified
24 version of that library), containing parts covered by the terms of the
25 OpenSSL or SSLeay licenses, the licensors of this Program grant you
26 additional permission to convey the resulting work. Corresponding
27 Source for a non-source form of such a combination shall include the
28 source code for the parts of OpenSSL used as well as that of the
29 covered work.
30 */
31
32 #include "config.h"
33
34 #include <cstdio>
35 #include <cstdlib>
36 #include <cstring>
37
38 #include <errno.h>
39 #include <netdb.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43
44 #include "netcompat.h"
45
46 #include <openssl/err.h>
47 #include <openssl/pem.h>
48 #include <openssl/rsa.h>
49 #include <openssl/rand.h>
50 #include <openssl/bn.h>
51
52 #include "conf.h"
53 #include "slog.h"
54 #include "util.h"
55
56 char *confbase;
57 char *thisnode;
58 char *identname;
59
60 struct configuration conf;
61
62 u8
63 best_protocol (u8 protset)
64 {
65 #if 1//D2
66 if (protset & PROT_IPv42 ) return PROT_IPv42;
67 #endif
68 if (protset & PROT_IPv4 ) return PROT_IPv4;
69 if (protset & PROT_ICMPv4) return PROT_ICMPv4;
70 if (protset & PROT_UDPv4 ) return PROT_UDPv4;
71 if (protset & PROT_TCPv4 ) return PROT_TCPv4;
72 if (protset & PROT_DNSv4 ) return PROT_DNSv4;
73
74 return 0;
75 }
76
77 const char *
78 strprotocol (u8 protocol)
79 {
80 #if 1//D2
81 if (protocol & PROT_IPv42 ) return "rawip2";
82 #endif
83 if (protocol & PROT_IPv4 ) return "rawip";
84 if (protocol & PROT_ICMPv4) return "icmp";
85 if (protocol & PROT_UDPv4 ) return "udp";
86 if (protocol & PROT_TCPv4 ) return "tcp";
87 if (protocol & PROT_DNSv4 ) return "dns";
88
89 return "<unknown>";
90 }
91
92 static bool
93 match_list (const vector<const char *> &list, const char *str)
94 {
95 for (vector<const char *>::const_iterator i = list.end (); i-- > list.begin (); )
96 if ((*i)[0] == '*' && !(*i)[1])
97 return true;
98 else if (!strcmp (*i, str))
99 return true;
100
101 return false;
102 }
103
104 bool
105 conf_node::may_direct (struct conf_node *other)
106 {
107 if (match_list (allow_direct, other->nodename))
108 return true;
109
110 if (match_list (deny_direct, other->nodename))
111 return false;
112
113 return true;
114 }
115
116 conf_node::~conf_node ()
117 {
118 #if 0
119 // does not work, because string pointers etc. are shared
120 // is not called, however
121 if (rsa_key)
122 RSA_free (rsa_key);
123
124 free (nodename);
125 free (hostname);
126 free (if_up_data);
127 #if ENABLE_DNS
128 free (domain);
129 free (dns_hostname);
130 #endif
131 #endif
132 }
133
134 void
135 configuration::init ()
136 {
137 memset (this, 0, sizeof (*this));
138
139 mtu = DEFAULT_MTU;
140 nfmark = 0;
141 rekey = DEFAULT_REKEY;
142 keepalive = DEFAULT_KEEPALIVE;
143 llevel = L_INFO;
144 ip_proto = IPPROTO_GRE;
145 #if 1 //D2
146 ip2_proto = 7;
147 #endif
148 #if ENABLE_ICMP
149 icmp_type = ICMP_ECHOREPLY;
150 #endif
151
152 default_node.udp_port = DEFAULT_UDPPORT;
153 default_node.tcp_port = DEFAULT_UDPPORT; // ehrm
154 default_node.connectmode = conf_node::C_ALWAYS;
155 default_node.compress = true;
156 default_node.protocols = 0;
157 default_node.max_retry = DEFAULT_MAX_RETRY;
158 default_node.max_ttl = DEFAULT_MAX_TTL;
159 default_node.max_queue = DEFAULT_MAX_QUEUE;
160 default_node.if_up_data = strdup ("");
161
162 #if ENABLE_DNS
163 default_node.dns_port = 0; // default is 0 == client
164
165 dns_case_preserving = true;
166 dns_forw_host = strdup ("127.0.0.1");
167 dns_forw_port = 53;
168 dns_timeout_factor = DEFAULT_DNS_TIMEOUT_FACTOR;
169 dns_send_interval = DEFAULT_DNS_SEND_INTERVAL;
170 dns_overlap_factor = DEFAULT_DNS_OVERLAP_FACTOR;
171 dns_max_outstanding = DEFAULT_DNS_MAX_OUTSTANDING;
172 #endif
173
174 conf.pidfilename = strdup (LOCALSTATEDIR "/run/gvpe.pid");
175 }
176
177 void
178 configuration::cleanup ()
179 {
180 if (rsa_key)
181 RSA_free (rsa_key);
182
183 rsa_key = 0;
184
185 free (pidfilename); pidfilename = 0;
186 free (ifname); ifname = 0;
187 #if ENABLE_HTTP_PROXY
188 free (proxy_host); proxy_host = 0;
189 free (proxy_auth); proxy_auth = 0;
190 #endif
191 #if ENABLE_DNS
192 free (dns_forw_host); dns_forw_host = 0;
193 #endif
194 free (script_if_up); script_if_up = 0;
195 free (script_node_up); script_node_up = 0;
196 free (script_node_change); script_node_change = 0;
197 free (script_node_down); script_node_down = 0;
198 }
199
200 void
201 configuration::clear ()
202 {
203 for (configuration::node_vector::iterator i = nodes.begin(); i != nodes.end(); ++i)
204 delete *i;
205
206 nodes.clear ();
207
208 cleanup ();
209 init ();
210 }
211
212 //static bool
213 //is_true (const char *name)
214 //{
215 //re
216 //}
217
218 #define parse_bool(target,name,trueval,falseval) do { \
219 if (!strcmp (val, "yes")) target = trueval; \
220 else if (!strcmp (val, "no")) target = falseval; \
221 else if (!strcmp (val, "true")) target = trueval; \
222 else if (!strcmp (val, "false")) target = falseval; \
223 else if (!strcmp (val, "on")) target = trueval; \
224 else if (!strcmp (val, "off")) target = falseval; \
225 else \
226 return _("illegal boolean value, only 'yes|true|on' or 'no|false|off' allowed, ignored"); \
227 } while (0)
228
229 const char *
230 configuration_parser::parse_line (char *line)
231 {
232 {
233 char *end = line + strlen (line);
234
235 while (*end < ' ' && end >= line)
236 end--;
237
238 *++end = 0;
239 }
240
241 char *tok = line;
242 const char *var = strtok (tok, "\t =");
243 tok = 0;
244
245 if (!var || !var[0])
246 return 0; /* no tokens on this line */
247
248 if (var[0] == '#')
249 return 0; /* comment: ignore */
250
251 char *val = strtok (NULL, "\t\n\r =");
252
253 if (!val || val[0] == '#')
254 return _("no value given for variable, ignored");
255
256 else if (!strcmp (var, "on"))
257 {
258 if (::thisnode
259 && ((val[0] == '!' && strcmp (val + 1, ::thisnode))
260 || !strcmp (val, ::thisnode)))
261 return parse_line (strtok (NULL, "\n\r"));
262 }
263
264 else if (!strcmp (var, "include"))
265 {
266 char *fname = conf.config_filename (val);
267 parse_file (fname);
268 free (fname);
269 }
270
271 // truly global
272 else if (!strcmp (var, "loglevel"))
273 {
274 loglevel l = string_to_loglevel (val);
275
276 if (l == L_NONE)
277 return _("unknown loglevel, ignored");
278 }
279 else if (!strcmp (var, "ip-proto"))
280 conf.ip_proto = atoi (val);
281 #if 1 //D2
282 else if (!strcmp (var, "ip2-proto"))
283 conf.ip2_proto = atoi (val);
284 #endif
285 else if (!strcmp (var, "icmp-type"))
286 {
287 #if ENABLE_ICMP
288 conf.icmp_type = atoi (val);
289 #endif
290 }
291
292 // per config
293 else if (!strcmp (var, "node"))
294 {
295 parse_argv ();
296
297 conf.default_node.id++;
298 node = new conf_node (conf.default_node);
299 conf.nodes.push_back (node);
300 node->nodename = strdup (val);
301
302 {
303 char *fname;
304 FILE *f;
305
306 asprintf (&fname, "%s/pubkey/%s", confbase, node->nodename);
307
308 f = fopen (fname, "r");
309 if (f)
310 {
311 node->rsa_key = RSA_new ();
312
313 if (!PEM_read_RSAPublicKey(f, &node->rsa_key, NULL, NULL))
314 {
315 ERR_load_RSA_strings (); ERR_load_PEM_strings ();
316 slog (L_ERR, _("unable to open public rsa key file '%s': %s"), fname, ERR_error_string (ERR_get_error (), 0));
317 exit (EXIT_FAILURE);
318 }
319
320 require (RSA_blinding_on (node->rsa_key, 0));
321
322 fclose (f);
323 }
324 else
325 {
326 slog (need_keys ? L_ERR : L_NOTICE, _("unable to read public rsa key file '%s': %s"), fname, strerror (errno));
327
328 if (need_keys)
329 exit (EXIT_FAILURE);
330 }
331
332 free (fname);
333 }
334
335 if (::thisnode && !strcmp (node->nodename, ::thisnode))
336 conf.thisnode = node;
337 }
338 else if (!strcmp (var, "private-key"))
339 free (conf.prikeyfile), conf.prikeyfile = strdup (val);
340 else if (!strcmp (var, "ifpersist"))
341 parse_bool (conf.ifpersist, "ifpersist", true, false);
342 else if (!strcmp (var, "ifname"))
343 free (conf.ifname), conf.ifname = strdup (val);
344 else if (!strcmp (var, "rekey"))
345 conf.rekey = atoi (val);
346 else if (!strcmp (var, "keepalive"))
347 conf.keepalive = atoi (val);
348 else if (!strcmp (var, "mtu"))
349 conf.mtu = atoi (val);
350 else if (!strcmp (var, "nfmark"))
351 conf.nfmark = atoi (val);
352 else if (!strcmp (var, "if-up"))
353 free (conf.script_if_up), conf.script_if_up = strdup (val);
354 else if (!strcmp (var, "node-up"))
355 free (conf.script_node_up), conf.script_node_up = strdup (val);
356 else if (!strcmp (var, "node-change"))
357 free (conf.script_node_change), conf.script_node_change = strdup (val);
358 else if (!strcmp (var, "node-down"))
359 free (conf.script_node_down), conf.script_node_down = strdup (val);
360 else if (!strcmp (var, "pid-file"))
361 free (conf.pidfilename), conf.pidfilename = strdup (val);
362 else if (!strcmp (var, "dns-forw-host"))
363 {
364 #if ENABLE_DNS
365 free (conf.dns_forw_host), conf.dns_forw_host = strdup (val);
366 #endif
367 }
368 else if (!strcmp (var, "dns-forw-port"))
369 {
370 #if ENABLE_DNS
371 conf.dns_forw_port = atoi (val);
372 #endif
373 }
374 else if (!strcmp (var, "dns-timeout-factor"))
375 {
376 #if ENABLE_DNS
377 conf.dns_timeout_factor = atof (val);
378 #endif
379 }
380 else if (!strcmp (var, "dns-send-interval"))
381 {
382 #if ENABLE_DNS
383 conf.dns_send_interval = atoi (val);
384 #endif
385 }
386 else if (!strcmp (var, "dns-overlap-factor"))
387 {
388 #if ENABLE_DNS
389 conf.dns_overlap_factor = atof (val);
390 #endif
391 }
392 else if (!strcmp (var, "dns-max-outstanding"))
393 {
394 #if ENABLE_DNS
395 conf.dns_max_outstanding = atoi (val);
396 #endif
397 }
398 else if (!strcmp (var, "dns-case-preserving"))
399 {
400 #if ENABLE_DNS
401 parse_bool (conf.dns_case_preserving, "dns-case-preserving", true, false);
402 #endif
403 }
404 else if (!strcmp (var, "http-proxy-host"))
405 {
406 #if ENABLE_HTTP_PROXY
407 free (conf.proxy_host), conf.proxy_host = strdup (val);
408 #endif
409 }
410 else if (!strcmp (var, "http-proxy-port"))
411 {
412 #if ENABLE_HTTP_PROXY
413 conf.proxy_port = atoi (val);
414 #endif
415 }
416 else if (!strcmp (var, "http-proxy-auth"))
417 {
418 #if ENABLE_HTTP_PROXY
419 conf.proxy_auth = (char *)base64_encode ((const u8 *)val, strlen (val));
420 #endif
421 }
422
423 /* node-specific, non-defaultable */
424 else if (node != &conf.default_node && !strcmp (var, "hostname"))
425 free (node->hostname), node->hostname = strdup (val);
426
427 /* node-specific, defaultable */
428 else if (!strcmp (var, "udp-port"))
429 node->udp_port = atoi (val);
430 else if (!strcmp (var, "tcp-port"))
431 node->tcp_port = atoi (val);
432 else if (!strcmp (var, "dns-hostname"))
433 {
434 #if ENABLE_DNS
435 free (node->dns_hostname), node->dns_hostname = strdup (val);
436 #endif
437 }
438 else if (!strcmp (var, "dns-port"))
439 {
440 #if ENABLE_DNS
441 node->dns_port = atoi (val);
442 #endif
443 }
444 else if (!strcmp (var, "dns-domain"))
445 {
446 #if ENABLE_DNS
447 free (node->domain), node->domain = strdup (val);
448 #endif
449 }
450 else if (!strcmp (var, "if-up-data"))
451 free (node->if_up_data), node->if_up_data = strdup (val);
452 else if (!strcmp (var, "router-priority"))
453 node->routerprio = atoi (val);
454 else if (!strcmp (var, "max-retry"))
455 node->max_retry = atoi (val);
456 else if (!strcmp (var, "connect"))
457 {
458 if (!strcmp (val, "ondemand"))
459 node->connectmode = conf_node::C_ONDEMAND;
460 else if (!strcmp (val, "never"))
461 node->connectmode = conf_node::C_NEVER;
462 else if (!strcmp (val, "always"))
463 node->connectmode = conf_node::C_ALWAYS;
464 else if (!strcmp (val, "disabled"))
465 node->connectmode = conf_node::C_DISABLED;
466 else
467 return _("illegal value for 'connectmode', use one of 'ondemand', 'never', 'always' or 'disabled', ignored");
468 }
469 else if (!strcmp (var, "inherit-tos"))
470 parse_bool (node->inherit_tos, "inherit-tos", true, false);
471 else if (!strcmp (var, "compress"))
472 parse_bool (node->compress, "compress", true, false);
473 // all these bool options really really cost a lot of executable size!
474 else if (!strcmp (var, "enable-tcp"))
475 {
476 #if ENABLE_TCP
477 u8 v; parse_bool (v, "enable-tcp" , PROT_TCPv4, 0); node->protocols = (node->protocols & ~PROT_TCPv4) | v;
478 #endif
479 }
480 else if (!strcmp (var, "enable-icmp"))
481 {
482 #if ENABLE_ICMP
483 u8 v; parse_bool (v, "enable-icmp" , PROT_ICMPv4, 0); node->protocols = (node->protocols & ~PROT_ICMPv4) | v;
484 #endif
485 }
486 else if (!strcmp (var, "enable-dns"))
487 {
488 #if ENABLE_DNS
489 u8 v; parse_bool (v, "enable-dns" , PROT_DNSv4, 0); node->protocols = (node->protocols & ~PROT_DNSv4) | v;
490 #endif
491 }
492 else if (!strcmp (var, "enable-udp"))
493 {
494 u8 v; parse_bool (v, "enable-udp" , PROT_UDPv4, 0); node->protocols = (node->protocols & ~PROT_UDPv4) | v;
495 }
496 else if (!strcmp (var, "enable-rawip"))
497 {
498 u8 v; parse_bool (v, "enable-rawip", PROT_IPv4, 0); node->protocols = (node->protocols & ~PROT_IPv4 ) | v;
499 }
500 #if 1//D2
501 else if (!strcmp (var, "enable-rawip2"))
502 {
503 u8 v; parse_bool (v, "enable-rawip2", PROT_IPv42, 0); node->protocols = (node->protocols & ~PROT_IPv42 ) | v;
504 }
505 #endif
506 else if (!strcmp (var, "allow-direct"))
507 node->allow_direct.push_back (strdup (val));
508 else if (!strcmp (var, "deny-direct"))
509 node->deny_direct.push_back (strdup (val));
510 else if (!strcmp (var, "max-ttl"))
511 node->max_ttl = atof (val);
512 else if (!strcmp (var, "max-queue"))
513 node->max_queue = atoi (val);
514
515 // unknown or misplaced
516 else
517 return _("unknown configuration directive - ignored");
518
519 return 0;
520 }
521
522 void
523 conf_node::finalise ()
524 {
525 if (max_queue < 1)
526 {
527 slog (L_WARN, _("%s: max-queue value invalid, setting it to 1."), nodename);
528 max_queue = 1;
529 }
530
531 if (routerprio > 1 && (connectmode != C_ALWAYS && connectmode != C_DISABLED))
532 {
533 //slog (L_WARN, _("%s: has non-zero router-priority but either 'never' or 'ondemand' as connectmode, setting it to 'always'."), nodename);
534 connectmode = C_ALWAYS;
535 }
536 }
537
538 void
539 configuration_parser::parse_argv ()
540 {
541 for (int i = 0; i < argc; ++i)
542 {
543 char *v = argv [i];
544
545 if (!*v)
546 continue;
547
548 char *enode = v;
549
550 while (*enode != '.' && *enode > ' ' && *enode != '=' && *enode)
551 enode++;
552
553 if (*enode != '.')
554 enode = 0;
555
556 char *wnode = node == &conf.default_node
557 ? 0
558 : node->nodename;
559
560 if ((!wnode && !enode)
561 || (wnode && enode && !strncmp (wnode, v, enode - v)))
562 {
563 const char *warn = parse_line (enode ? enode + 1 : v);
564
565 if (warn)
566 slog (L_WARN, _("%s, while parsing command line option '%s'."), warn, v);
567
568 *v = 0;
569 }
570 }
571 }
572
573 void
574 configuration_parser::parse_file (const char *fname)
575 {
576 if (FILE *f = fopen (fname, "r"))
577 {
578 char line [2048];
579 int lineno = 0;
580
581 while (fgets (line, sizeof (line), f))
582 {
583 lineno++;
584
585 const char *warn = parse_line (line);
586
587 if (warn)
588 slog (L_WARN, _("%s, at '%s', line %d."), warn, fname, lineno);
589 }
590
591 fclose (f);
592
593 parse_argv ();
594 }
595 else
596 {
597 slog (L_ERR, _("unable to read config file '%s': %s"), fname, strerror (errno));
598 exit (EXIT_FAILURE);
599 }
600 }
601
602 configuration_parser::configuration_parser (configuration &conf,
603 bool need_keys,
604 int argc,
605 char **argv)
606 : conf (conf),need_keys (need_keys), argc (argc), argv (argv)
607 {
608 char *fname;
609
610 conf.clear ();
611 node = &conf.default_node;
612
613 asprintf (&fname, "%s/gvpe.conf", confbase);
614 parse_file (fname);
615 free (fname);
616
617 fname = conf.config_filename (conf.prikeyfile, "hostkey");
618
619 if (FILE *f = fopen (fname, "r"))
620 {
621 conf.rsa_key = RSA_new ();
622
623 if (!PEM_read_RSAPrivateKey (f, &conf.rsa_key, NULL, NULL))
624 {
625 ERR_load_RSA_strings (); ERR_load_PEM_strings ();
626 slog (L_ERR, _("unable to read private rsa key file '%s': %s"), fname, ERR_error_string (ERR_get_error (), 0));
627 exit (EXIT_FAILURE);
628 }
629
630 require (RSA_blinding_on (conf.rsa_key, 0));
631
632 fclose (f);
633 }
634 else
635 {
636 slog (need_keys ? L_ERR : L_NOTICE, _("unable to open private rsa key file '%s': %s"), fname, strerror (errno));
637
638 if (need_keys)
639 exit (EXIT_FAILURE);
640 }
641
642 free (fname);
643
644 if (need_keys && ::thisnode
645 && conf.rsa_key && conf.thisnode && conf.thisnode->rsa_key)
646 if (BN_cmp (conf.rsa_key->n, conf.thisnode->rsa_key->n) != 0
647 || BN_cmp (conf.rsa_key->e, conf.thisnode->rsa_key->e) != 0)
648 {
649 slog (L_NOTICE, _("private hostkey and public node key mismatch: is '%s' the correct node?"), ::thisnode);
650 exit (EXIT_FAILURE);
651 }
652
653 for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i)
654 (*i)->finalise ();
655 }
656
657 char *
658 configuration::config_filename (const char *name, const char *dflt)
659 {
660 char *fname;
661
662 asprintf (&fname, name ? name : dflt, ::thisnode);
663
664 if (!ABSOLUTE_PATH (fname))
665 {
666 char *rname = fname;
667 asprintf (&fname, "%s/%s", confbase, rname);
668 free (rname);
669 }
670
671 return fname;
672 }
673
674 void
675 conf_node::print ()
676 {
677 printf ("%4d fe:fd:80:00:0%1x:%02x %c %-8.8s %-10.10s %02x %s%s%d\n",
678 id,
679 id >> 8, id & 0xff,
680 compress ? 'Y' : 'N',
681 connectmode == C_ONDEMAND ? "ondemand"
682 : connectmode == C_NEVER ? "never"
683 : connectmode == C_ALWAYS ? "always"
684 : connectmode == C_DISABLED ? "disabled"
685 : "",
686 nodename,
687 protocols,
688 hostname ? hostname : "",
689 hostname ? ":" : "",
690 hostname ? udp_port : 0
691 );
692 }
693
694 void
695 configuration::print ()
696 {
697 printf (_("\nConfiguration\n\n"));
698 printf (_("# of nodes: %d\n"), nodes.size ());
699 printf (_("this node: %s\n"), thisnode ? thisnode->nodename : "<unset>");
700 printf (_("MTU: %d\n"), mtu);
701 printf (_("rekeying interval: %d\n"), rekey);
702 printf (_("keepalive interval: %d\n"), keepalive);
703 printf (_("interface: %s\n"), ifname);
704 printf (_("primary rsa key: %s\n"), prikeyfile ? prikeyfile : "<default>");
705 printf (_("rsa key size: %d\n"), rsa_key ? RSA_size (rsa_key) * 8 : -1);
706 printf ("\n");
707
708 printf ("%4s %-17s %s %-8.8s %-10.10s %04s %s\n",
709 _("ID#"), _("MAC"), _("Com"), _("Conmode"), _("Node"), _("Prot"), _("Host:Port"));
710
711 for (node_vector::iterator i = nodes.begin (); i != nodes.end (); ++i)
712 (*i)->print ();
713
714 printf ("\n");
715 }
716
717 configuration::configuration ()
718 {
719 asprintf (&confbase, "%s/gvpe", CONFDIR);
720
721 init ();
722 }
723
724 configuration::~configuration ()
725 {
726 cleanup ();
727 }
728