--- gvpe/src/conf.C 2003/03/09 12:40:18 1.3 +++ gvpe/src/conf.C 2013/07/18 13:35:16 1.63 @@ -1,24 +1,32 @@ /* - conf.c -- configuration code - Copyright (C) 1998 Robert van der Meulen - 1998-2002 Ivo Timmermans - 2000-2002 Guus Sliepen - 2000 Cris van Pelt - 2003 Marc Lehmann + conf.C -- configuration code + Copyright (C) 2003-2008,2011 Marc Lehmann - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + This file is part of GVPE. + + GVPE is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 3 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, see . + + Additional permission under GNU GPL version 3 section 7 + + If you modify this Program, or any covered work, by linking or + combining it with the OpenSSL project's OpenSSL library (or a modified + version of that library), containing parts covered by the terms of the + OpenSSL or SSLeay licenses, the licensors of this Program grant you + additional permission to convey the resulting work. Corresponding + Source for a non-source form of such a combination shall include the + source code for the parts of OpenSSL used as well as that of the + covered work. */ #include "config.h" @@ -32,13 +40,15 @@ #include #include #include +#include + +#include "netcompat.h" #include #include #include #include - -#include "gettext.h" +#include #include "conf.h" #include "slog.h" @@ -47,46 +57,144 @@ char *confbase; char *thisnode; char *identname; -char *pidfilename; struct configuration conf; -configuration::configuration () +u8 +best_protocol (u8 protset) { - init (); + if (protset & PROT_IPv4 ) return PROT_IPv4; + if (protset & PROT_ICMPv4) return PROT_ICMPv4; + if (protset & PROT_UDPv4 ) return PROT_UDPv4; + if (protset & PROT_TCPv4 ) return PROT_TCPv4; + if (protset & PROT_DNSv4 ) return PROT_DNSv4; + + return 0; } -configuration::~configuration () +const char * +strprotocol (u8 protocol) { - cleanup (); + if (protocol & PROT_IPv4 ) return "rawip"; + if (protocol & PROT_ICMPv4) return "icmp"; + if (protocol & PROT_UDPv4 ) return "udp"; + if (protocol & PROT_TCPv4 ) return "tcp"; + if (protocol & PROT_DNSv4 ) return "dns"; + + return ""; +} + +static bool +match_list (const vector &list, const char *str) +{ + for (vector::const_iterator i = list.end (); i-- > list.begin (); ) + if ((*i)[0] == '*' && !(*i)[1]) + return true; + else if (!strcmp (*i, str)) + return true; + + return false; +} + +bool +conf_node::may_direct (struct conf_node *other) +{ + if (match_list (allow_direct, other->nodename)) + return true; + + if (match_list (deny_direct, other->nodename)) + return false; + + return true; +} + +conf_node::~conf_node () +{ +#if 0 + // does not work, because string pointers etc. are shared + // is not called, however + if (rsa_key) + RSA_free (rsa_key); + + free (nodename); + free (hostname); + free (if_up_data); +#if ENABLE_DNS + free (domain); + free (dns_hostname); +#endif +#endif } -void configuration::init () +void +configuration::init () { memset (this, 0, sizeof (*this)); + mtu = DEFAULT_MTU; + nfmark = 0; rekey = DEFAULT_REKEY; keepalive = DEFAULT_KEEPALIVE; llevel = L_INFO; + ip_proto = IPPROTO_GRE; +#if ENABLE_ICMP + icmp_type = ICMP_ECHOREPLY; +#endif - default_node.port = DEFAULT_PORT; + default_node.udp_port = DEFAULT_UDPPORT; + default_node.tcp_port = DEFAULT_UDPPORT; // ehrm default_node.connectmode = conf_node::C_ALWAYS; default_node.compress = true; + default_node.protocols = 0; + default_node.max_retry = DEFAULT_MAX_RETRY; + default_node.max_ttl = DEFAULT_MAX_TTL; + default_node.max_queue = DEFAULT_MAX_QUEUE; + default_node.if_up_data = strdup (""); + +#if ENABLE_DNS + default_node.dns_port = 0; // default is 0 == client + + dns_case_preserving = true; + dns_forw_host = strdup ("127.0.0.1"); + dns_forw_port = 53; + dns_timeout_factor = DEFAULT_DNS_TIMEOUT_FACTOR; + dns_send_interval = DEFAULT_DNS_SEND_INTERVAL; + dns_overlap_factor = DEFAULT_DNS_OVERLAP_FACTOR; + dns_max_outstanding = DEFAULT_DNS_MAX_OUTSTANDING; +#endif + + pidfilename = strdup (LOCALSTATEDIR "/run/gvpe.pid"); + seed_dev = strdup ("/dev/urandom"); + reseed = DEFAULT_RESEED; } -void configuration::cleanup() +void +configuration::cleanup () { if (rsa_key) RSA_free (rsa_key); - free (ifname); - rsa_key = 0; - ifname = 0; + + free (seed_dev); seed_dev = 0; + free (pidfilename); pidfilename = 0; + free (ifname); ifname = 0; +#if ENABLE_HTTP_PROXY + free (proxy_host); proxy_host = 0; + free (proxy_auth); proxy_auth = 0; +#endif +#if ENABLE_DNS + free (dns_forw_host); dns_forw_host = 0; +#endif + free (change_root); change_root = 0; + free (script_if_up); script_if_up = 0; + free (script_node_up); script_node_up = 0; + free (script_node_change); script_node_change = 0; + free (script_node_down); script_node_down = 0; } void -configuration::clear_config () +configuration::clear () { for (configuration::node_vector::iterator i = nodes.begin(); i != nodes.end(); ++i) delete *i; @@ -97,210 +205,340 @@ init (); } -void configuration::read_config (bool need_keys) +conf_node * +configuration::find_node (const char *name) { - char *fname; - FILE *f; - - clear_config (); - - asprintf (&fname, "%s/vped.conf", confbase); - f = fopen (fname, "r"); - - if (f) - { - char line[16384]; - int lineno = 0; - char *var, *val; - conf_node *node = &default_node; + for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i) + if (!strcmp ((*i)->nodename, name)) + return *i; - while (fgets (line, sizeof (line), f)) - { - lineno++; + return 0; +} - { - char *end = line + strlen (line); +//static bool +//is_true (const char *name) +//{ + //re +//} + +#define parse_bool(target,name,trueval,falseval) do { \ + if (!strcmp (val, "yes")) target = trueval; \ + else if (!strcmp (val, "no")) target = falseval; \ + else if (!strcmp (val, "true")) target = trueval; \ + else if (!strcmp (val, "false")) target = falseval; \ + else if (!strcmp (val, "on")) target = trueval; \ + else if (!strcmp (val, "off")) target = falseval; \ + else \ + return _("illegal boolean value, only 'yes|true|on' or 'no|false|off' allowed, ignored"); \ +} while (0) - while (*end < ' ' && end >= line) - end--; +const char * +configuration_parser::parse_line (char *line) +{ + { + char *end = line + strlen (line); - *++end = 0; - } + while (*end < ' ' && end >= line) + end--; - char *tok = line; + *++end = 0; + } -retry: - var = strtok (tok, "\t ="); - tok = 0; + char *tok = line; + const char *var = strtok (tok, "\t ="); + tok = 0; - if (!var || !var[0]) - continue; /* no tokens on this line */ + if (!var || !var[0]) + return 0; /* no tokens on this line */ - if (var[0] == '#') - continue; /* comment: ignore */ + if (var[0] == '#') + return 0; /* comment: ignore */ - val = strtok (NULL, "\t\n\r ="); + if (!strcmp (var, "global")) + { + node = &conf.default_node; + return 0; + } - if (!val || val[0] == '#') - { - slog (L_WARN, - _("no value for variable `%s', at '%s' line %d"), - var, fname, lineno); - break; - } + char *val = strtok (NULL, "\t\n\r ="); - if (!strcmp (var, "on")) - { - if (!::thisnode - || (val[0] == '!' && strcmp (val + 1, ::thisnode)) - || !strcmp (val, ::thisnode)) - goto retry; + if (!val || val[0] == '#') + return _("no value given for variable, ignored"); - continue; - } + else if (!strcmp (var, "on")) + { + if (::thisnode + && ((val[0] == '!' && strcmp (val + 1, ::thisnode)) + || !strcmp (val, ::thisnode))) + return parse_line (strtok (NULL, "\n\r")); + } - // truly global - if (!strcmp (var, "loglevel")) - { - loglevel l = string_to_loglevel (val); + else if (!strcmp (var, "include")) + { + char *fname = conf.config_filename (val); + parse_file (fname); + free (fname); + } - if (l != L_NONE) - llevel = l; - else - slog (L_WARN, "'%s': %s, at '%s' line %d", val, UNKNOWN_LOGLEVEL, fname, line); - } + // truly global + else if (!strcmp (var, "loglevel")) + { + loglevel l = string_to_loglevel (val); - // per config - else if (!strcmp (var, "node")) - { - default_node.id++; + if (l == L_NONE) + return _("unknown loglevel, ignored"); + } + else if (!strcmp (var, "ip-proto")) + conf.ip_proto = atoi (val); + else if (!strcmp (var, "icmp-type")) + { +#if ENABLE_ICMP + conf.icmp_type = atoi (val); +#endif + } + else if (!strcmp (var, "chuser")) + { + struct passwd *pw = getpwnam (val); + if (!pw) + return _("user specified for chuser not found"); - node = new conf_node (default_node); + conf.change_uid = pw->pw_uid; + conf.change_gid = pw->pw_gid; + } + else if (!strcmp (var, "chuid")) + conf.change_uid = atoi (val); + else if (!strcmp (var, "chgid")) + conf.change_gid = atoi (val); + else if (!strcmp (var, "chroot")) + free (conf.change_root), conf.change_root = strdup (val); - nodes.push_back (node); + // per node + else if (!strcmp (var, "node")) + { + node = conf.find_node (val); - node->nodename = strdup (val); + if (!node) + { + conf.default_node.id++; + node = new conf_node (conf.default_node); + conf.nodes.push_back (node); + node->nodename = strdup (val); + } + } + else if (!strcmp (var, "private-key")) + free (conf.prikeyfile), conf.prikeyfile = strdup (val); + else if (!strcmp (var, "ifpersist")) + parse_bool (conf.ifpersist, "ifpersist", true, false); + else if (!strcmp (var, "ifname")) + free (conf.ifname), conf.ifname = strdup (val); + else if (!strcmp (var, "rekey")) + conf.rekey = atoi (val); + else if (!strcmp (var, "keepalive")) + conf.keepalive = atoi (val); + else if (!strcmp (var, "mtu")) + conf.mtu = atoi (val); + else if (!strcmp (var, "nfmark")) + conf.nfmark = atoi (val); + else if (!strcmp (var, "seed-device")) + free (conf.seed_dev), conf.seed_dev = strdup (val); + else if (!strcmp (var, "seed-interval")) + conf.reseed = atoi (val); + else if (!strcmp (var, "if-up")) + free (conf.script_if_up), conf.script_if_up = strdup (val); + else if (!strcmp (var, "node-up")) + free (conf.script_node_up), conf.script_node_up = strdup (val); + else if (!strcmp (var, "node-change")) + free (conf.script_node_change), conf.script_node_change = strdup (val); + else if (!strcmp (var, "node-down")) + free (conf.script_node_down), conf.script_node_down = strdup (val); + else if (!strcmp (var, "pid-file")) + free (conf.pidfilename), conf.pidfilename = strdup (val); + else if (!strcmp (var, "dns-forw-host")) + { +#if ENABLE_DNS + free (conf.dns_forw_host), conf.dns_forw_host = strdup (val); +#endif + } + else if (!strcmp (var, "dns-forw-port")) + { +#if ENABLE_DNS + conf.dns_forw_port = atoi (val); +#endif + } + else if (!strcmp (var, "dns-timeout-factor")) + { +#if ENABLE_DNS + conf.dns_timeout_factor = atof (val); +#endif + } + else if (!strcmp (var, "dns-send-interval")) + { +#if ENABLE_DNS + conf.dns_send_interval = atoi (val); +#endif + } + else if (!strcmp (var, "dns-overlap-factor")) + { +#if ENABLE_DNS + conf.dns_overlap_factor = atof (val); +#endif + } + else if (!strcmp (var, "dns-max-outstanding")) + { +#if ENABLE_DNS + conf.dns_max_outstanding = atoi (val); +#endif + } + else if (!strcmp (var, "dns-case-preserving")) + { +#if ENABLE_DNS + parse_bool (conf.dns_case_preserving, "dns-case-preserving", true, false); +#endif + } + else if (!strcmp (var, "http-proxy-host")) + { +#if ENABLE_HTTP_PROXY + free (conf.proxy_host), conf.proxy_host = strdup (val); +#endif + } + else if (!strcmp (var, "http-proxy-port")) + { +#if ENABLE_HTTP_PROXY + conf.proxy_port = atoi (val); +#endif + } + else if (!strcmp (var, "http-proxy-auth")) + { +#if ENABLE_HTTP_PROXY + conf.proxy_auth = (char *)base64_encode ((const u8 *)val, strlen (val)); +#endif + } - { - char *fname; - FILE *f; + /* node-specific, non-defaultable */ + else if (node != &conf.default_node && !strcmp (var, "hostname")) + free (node->hostname), node->hostname = strdup (val); + + /* node-specific, defaultable */ + else if (!strcmp (var, "udp-port")) + node->udp_port = atoi (val); + else if (!strcmp (var, "tcp-port")) + node->tcp_port = atoi (val); + else if (!strcmp (var, "dns-hostname")) + { +#if ENABLE_DNS + free (node->dns_hostname), node->dns_hostname = strdup (val); +#endif + } + else if (!strcmp (var, "dns-port")) + { +#if ENABLE_DNS + node->dns_port = atoi (val); +#endif + } + else if (!strcmp (var, "dns-domain")) + { +#if ENABLE_DNS + free (node->domain), node->domain = strdup (val); +#endif + } + else if (!strcmp (var, "if-up-data")) + free (node->if_up_data), node->if_up_data = strdup (val); + else if (!strcmp (var, "router-priority")) + node->routerprio = atoi (val); + else if (!strcmp (var, "max-retry")) + node->max_retry = atoi (val); + else if (!strcmp (var, "connect")) + { + if (!strcmp (val, "ondemand")) + node->connectmode = conf_node::C_ONDEMAND; + else if (!strcmp (val, "never")) + node->connectmode = conf_node::C_NEVER; + else if (!strcmp (val, "always")) + node->connectmode = conf_node::C_ALWAYS; + else if (!strcmp (val, "disabled")) + node->connectmode = conf_node::C_DISABLED; + else + return _("illegal value for 'connectmode', use one of 'ondemand', 'never', 'always' or 'disabled', ignored"); + } + else if (!strcmp (var, "inherit-tos")) + parse_bool (node->inherit_tos, "inherit-tos", true, false); + else if (!strcmp (var, "compress")) + parse_bool (node->compress, "compress", true, false); + // all these bool options really really cost a lot of executable size! + else if (!strcmp (var, "enable-tcp")) + { +#if ENABLE_TCP + u8 v; parse_bool (v, "enable-tcp" , PROT_TCPv4, 0); node->protocols = (node->protocols & ~PROT_TCPv4) | v; +#endif + } + else if (!strcmp (var, "enable-icmp")) + { +#if ENABLE_ICMP + u8 v; parse_bool (v, "enable-icmp" , PROT_ICMPv4, 0); node->protocols = (node->protocols & ~PROT_ICMPv4) | v; +#endif + } + else if (!strcmp (var, "enable-dns")) + { +#if ENABLE_DNS + u8 v; parse_bool (v, "enable-dns" , PROT_DNSv4, 0); node->protocols = (node->protocols & ~PROT_DNSv4) | v; +#endif + } + else if (!strcmp (var, "enable-udp")) + { + u8 v; parse_bool (v, "enable-udp" , PROT_UDPv4, 0); node->protocols = (node->protocols & ~PROT_UDPv4) | v; + } + else if (!strcmp (var, "enable-rawip")) + { + u8 v; parse_bool (v, "enable-rawip", PROT_IPv4, 0); node->protocols = (node->protocols & ~PROT_IPv4 ) | v; + } + else if (!strcmp (var, "allow-direct")) + node->allow_direct.push_back (strdup (val)); + else if (!strcmp (var, "deny-direct")) + node->deny_direct.push_back (strdup (val)); + else if (!strcmp (var, "max-ttl")) + node->max_ttl = atof (val); + else if (!strcmp (var, "max-queue")) + node->max_queue = atoi (val); - asprintf (&fname, "%s/pubkey/%s", confbase, node->nodename); + // unknown or misplaced + else + return _("unknown configuration directive - ignored"); - f = fopen (fname, "r"); - if (f) - { - node->rsa_key = RSA_new (); - - if (!PEM_read_RSAPublicKey(f, &node->rsa_key, NULL, NULL)) - { - ERR_load_RSA_strings (); ERR_load_PEM_strings (); - slog (L_ERR, _("unable to open public rsa key file '%s': %s"), fname, ERR_error_string (ERR_get_error (), 0)); - exit (1); - } - - RSA_blinding_on (node->rsa_key, 0); - - fclose (f); - } - else - { - slog (need_keys ? L_ERR : L_NOTICE, _("unable to read public rsa key file '%s': %s"), fname, strerror (errno)); - - if (need_keys) - exit (1); - } + return 0; +} - free (fname); - } +void +conf_node::finalise () +{ + if (max_queue < 1) + { + slog (L_WARN, _("%s: max-queue value invalid, setting it to 1."), nodename); + max_queue = 1; + } - if (!::thisnode || !strcmp (node->nodename, ::thisnode)) - thisnode = node; - } - else if (!strcmp (var, "private-key")) - prikeyfile = strdup (val); - else if (!strcmp (var, "ifpersist")) - { - if (!strcmp (val, "yes")) - ifpersist = true; - else if (!strcmp (val, "no")) - ifpersist = false; - else - slog (L_WARN, - _("illegal value for 'ifpersist', only 'yes' or 'no' allowed, at '%s' line %d"), - var, fname, lineno); - } - else if (!strcmp (var, "ifname")) - ifname = strdup (val); - else if (!strcmp (var, "rekey")) - rekey = atoi (val); - else if (!strcmp (var, "keepalive")) - keepalive = atoi (val); - else if (!strcmp (var, "mtu")) - mtu = atoi (val); - else if (!strcmp (var, "if-up")) - script_if_up = strdup (val); - else if (!strcmp (var, "node-up")) - script_node_up = strdup (val); - else if (!strcmp (var, "node-down")) - script_node_down = strdup (val); + if (routerprio > 1 && (connectmode != C_ALWAYS && connectmode != C_DISABLED)) + { + //slog (L_WARN, _("%s: has non-zero router-priority but either 'never' or 'ondemand' as connectmode, setting it to 'always'."), nodename); + connectmode = C_ALWAYS; + } +} - /* node-specific, non-defaultable */ - else if (node != &default_node && !strcmp (var, "hostname")) - { - free (node->hostname); - node->hostname = strdup (val); - } +void +configuration_parser::parse_file (const char *fname) +{ + if (FILE *f = fopen (fname, "r")) + { + char line [2048]; + int lineno = 0; - /* node-specific, defaultable */ - else if (!strcmp (var, "port")) - node->port = atoi (val); - else if (!strcmp (var, "router-priority")) - node->routerprio = atoi (val); - else if (!strcmp (var, "connect")) - { - if (!strcmp (val, "ondemand")) - node->connectmode = conf_node::C_ONDEMAND; - else if (!strcmp (val, "never")) - node->connectmode = conf_node::C_NEVER; - else if (!strcmp (val, "always")) - node->connectmode = conf_node::C_ALWAYS; - else - slog (L_WARN, - _("illegal value for 'connectmode', use one of 'ondemand', 'never' or 'always', at '%s' line %d"), - var, fname, lineno); - } - else if (!strcmp (var, "inherit-tos")) - { - if (!strcmp (val, "yes")) - node->inherit_tos = true; - else if (!strcmp (val, "no")) - node->inherit_tos = false; - else - slog (L_WARN, - _("illegal value for 'compress', only 'yes' or 'no' allowed, at '%s' line %d"), - var, fname, lineno); - } + while (fgets (line, sizeof (line), f)) + { + lineno++; - else if (!strcmp (var, "compress")) - { - if (!strcmp (val, "yes")) - node->compress = true; - else if (!strcmp (val, "no")) - node->compress = false; - else - slog (L_WARN, - _("illegal value for 'compress', only 'yes' or 'no' allowed, at '%s' line %d"), - var, fname, lineno); - } + const char *warn = parse_line (line); - // unknown or misplaced - else - { - slog (L_WARN, - _("unknown or misplaced variable `%s', at '%s' line %d"), - var, fname, lineno); - } + if (warn) + slog (L_WARN, _("%s, at '%s', line %d."), warn, fname, lineno); } fclose (f); @@ -308,45 +546,165 @@ else { slog (L_ERR, _("unable to read config file '%s': %s"), fname, strerror (errno)); - exit (1); + exit (EXIT_FAILURE); } +} + +configuration_parser::configuration_parser (configuration &conf, + bool need_keys, + int argc, + char **argv) +: conf (conf), need_keys (need_keys), argc (argc), argv (argv) +{ + char *fname; + + conf.clear (); + node = &conf.default_node; + asprintf (&fname, "%s/gvpe.conf", confbase); + parse_file (fname); free (fname); - fname = config_filename (prikeyfile, "hostkey"); + fname = conf.config_filename (conf.prikeyfile, "hostkey"); - f = fopen (fname, "r"); - if (f) + if (FILE *f = fopen (fname, "r")) { - rsa_key = RSA_new (); + conf.rsa_key = RSA_new (); - if (!PEM_read_RSAPrivateKey (f, &rsa_key, NULL, NULL)) + if (!PEM_read_RSAPrivateKey (f, &conf.rsa_key, NULL, NULL)) { ERR_load_RSA_strings (); ERR_load_PEM_strings (); slog (L_ERR, _("unable to read private rsa key file '%s': %s"), fname, ERR_error_string (ERR_get_error (), 0)); - exit (1); + exit (EXIT_FAILURE); } - RSA_blinding_on (rsa_key, 0); + require (RSA_blinding_on (conf.rsa_key, 0)); fclose (f); } else { - slog (need_keys ? L_ERR : L_NOTICE, _("unable to open private rsa key file '%s': %s"), fname, strerror (errno)); - if (need_keys) - exit (1); + { + slog (need_keys ? L_ERR : L_NOTICE, _("unable to open private rsa key file '%s': %s"), fname, strerror (errno)); + exit (EXIT_FAILURE); + } } free (fname); + + fname = conf.config_filename (conf.pidfilename); + free (conf.pidfilename); conf.pidfilename = fname; + + for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i) + { + conf_node *node = *i; + char *fname; + FILE *f; + + asprintf (&fname, "%s/pubkey/%s", confbase, node->nodename); + + f = fopen (fname, "r"); + if (f) + { + node->rsa_key = RSA_new (); + + if (!PEM_read_RSAPublicKey (f, &node->rsa_key, NULL, NULL)) + { + ERR_load_RSA_strings (); ERR_load_PEM_strings (); + slog (L_ERR, _("unable to open public rsa key file '%s': %s"), fname, ERR_error_string (ERR_get_error (), 0)); + exit (EXIT_FAILURE); + } + + require (RSA_blinding_on (node->rsa_key, 0)); + + fclose (f); + } + else + { + slog (need_keys ? L_ERR : L_NOTICE, _("unable to read public rsa key file '%s': %s"), fname, strerror (errno)); + + if (need_keys) + exit (EXIT_FAILURE); + } + + free (fname); + + (*i)->finalise (); + } + + if (::thisnode) + { + conf.thisnode = conf.find_node (::thisnode); + + if (need_keys) + { + if (!conf.thisnode) + { + slog (L_NOTICE, _("local node ('%s') not found in config file, aborting."), ::thisnode); + exit (EXIT_FAILURE); + } + + if (conf.rsa_key && conf.thisnode->rsa_key) + if (BN_cmp (conf.rsa_key->n, conf.thisnode->rsa_key->n) != 0 + || BN_cmp (conf.rsa_key->e, conf.thisnode->rsa_key->e) != 0) + { + slog (L_NOTICE, _("private hostkey and public node key mismatch: is '%s' the correct node?"), ::thisnode); + exit (EXIT_FAILURE); + } + } + } + + parse_argv (); +} + +void +configuration_parser::parse_argv () +{ + for (int i = 0; i < argc; ++i) + { + char *v = argv [i]; + + if (!*v) + continue; + + char *enode = v; + + while (*enode != '.' && *enode > ' ' && *enode != '=' && *enode) + enode++; + + if (*enode != '.') + enode = 0; + + if (enode) + { + char *val = strdup (v); + val [enode - v] = 0; + node = conf.find_node (val); + free (val); + + if (!node) + { + slog (L_WARN, _("command line option '%s' refers to unknown node, ignoring."), v); + continue; + } + } + else + node = &conf.default_node; + + const char *warn = parse_line (enode ? enode + 1 : v); + + if (warn) + slog (L_WARN, _("%s, while parsing command line option '%s'."), warn, v); + } } -char *configuration::config_filename (const char *name, const char *dflt) +char * +configuration::config_filename (const char *name, const char *dflt) { char *fname; - asprintf (&fname, name ? name : dflt, ::thisnode); + asprintf (&fname, name ? name : dflt, ::thisnode ? ::thisnode : ""); if (!ABSOLUTE_PATH (fname)) { @@ -359,6 +717,26 @@ } void +conf_node::print () +{ + printf ("%4d fe:fd:80:00:0%1x:%02x %c %-8.8s %-10.10s %02x %s%s%d\n", + id, + id >> 8, id & 0xff, + compress ? 'Y' : 'N', + connectmode == C_ONDEMAND ? "ondemand" + : connectmode == C_NEVER ? "never" + : connectmode == C_ALWAYS ? "always" + : connectmode == C_DISABLED ? "disabled" + : "", + nodename, + protocols, + hostname ? hostname : "", + hostname ? ":" : "", + hostname ? udp_port : 0 + ); +} + +void configuration::print () { printf (_("\nConfiguration\n\n")); @@ -369,11 +747,11 @@ printf (_("keepalive interval: %d\n"), keepalive); printf (_("interface: %s\n"), ifname); printf (_("primary rsa key: %s\n"), prikeyfile ? prikeyfile : ""); - printf (_("rsa key size: %d\n"), rsa_key ? RSA_size (rsa_key) : -1); + printf (_("rsa key size: %d\n"), rsa_key ? RSA_size (rsa_key) * 8 : -1); printf ("\n"); - printf ("%4s %-17s %s %-8.8s %-10.10s %s\n", - _("ID#"), _("MAC"), _("Com"), _("Conmode"), _("Node"), _("Host:Port")); + printf ("%4s %-17s %s %-8.8s %-10.10s %04s %s\n", + _("ID#"), _("MAC"), _("Com"), _("Conmode"), _("Node"), _("Prot"), _("Host:Port")); for (node_vector::iterator i = nodes.begin (); i != nodes.end (); ++i) (*i)->print (); @@ -381,20 +759,15 @@ printf ("\n"); } -void -conf_node::print () +configuration::configuration () { - printf ("%4d fe:fd:80:00:0%1x:%02x %c %-8.8s %-10.10s %s%s%d\n", - id, - id >> 8, id & 0xff, - compress ? 'Y' : 'N', - connectmode == C_ONDEMAND ? "ondemand" : - connectmode == C_NEVER ? "never" : - connectmode == C_ALWAYS ? "always" : "", - nodename, - hostname ? hostname : "", - hostname ? ":" : "", - hostname ? port : 0 - ); + asprintf (&confbase, "%s/gvpe", CONFDIR); + + init (); +} + +configuration::~configuration () +{ + cleanup (); }