--- gvpe/src/conf.C 2009/07/18 05:59:16 1.51 +++ gvpe/src/conf.C 2015/07/30 19:03:44 1.66 @@ -1,6 +1,6 @@ /* - conf.c -- configuration code - Copyright (C) 2003-2008 Marc Lehmann + conf.C -- configuration code + Copyright (C) 2003-2008,2011 Marc Lehmann This file is part of GVPE. @@ -40,6 +40,7 @@ #include #include #include +#include #include "netcompat.h" @@ -59,7 +60,8 @@ struct configuration conf; -u8 best_protocol (u8 protset) +u8 +best_protocol (u8 protset) { if (protset & PROT_IPv4 ) return PROT_IPv4; if (protset & PROT_ICMPv4) return PROT_ICMPv4; @@ -70,7 +72,8 @@ return 0; } -const char *strprotocol (u8 protocol) +const char * +strprotocol (u8 protocol) { if (protocol & PROT_IPv4 ) return "rawip"; if (protocol & PROT_ICMPv4) return "icmp"; @@ -105,25 +108,6 @@ return true; } -void -conf_node::print () -{ - 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" - : connectmode == C_DISABLED ? "disabled" - : "", - nodename, - hostname ? hostname : "", - hostname ? ":" : "", - hostname ? udp_port : 0 - ); -} - conf_node::~conf_node () { #if 0 @@ -142,7 +126,8 @@ #endif } -void configuration::init () +void +configuration::init () { memset (this, 0, sizeof (*this)); @@ -169,6 +154,7 @@ #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; @@ -177,25 +163,30 @@ dns_max_outstanding = DEFAULT_DNS_MAX_OUTSTANDING; #endif - conf.pidfilename = strdup (LOCALSTATEDIR "/run/gvpe.pid"); + 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); rsa_key = 0; + free (seed_dev); seed_dev = 0; free (pidfilename); pidfilename = 0; free (ifname); ifname = 0; -#if ENABLE_HTTP_PROXY +#if ENABLE_HTTP_PROXY free (proxy_host); proxy_host = 0; free (proxy_auth); proxy_auth = 0; -#endif -#if ENABLE_DNS +#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; @@ -214,6 +205,22 @@ init (); } +conf_node * +configuration::find_node (const char *name) +{ + for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i) + if (!strcmp ((*i)->nodename, name)) + return *i; + + return 0; +} + +//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; \ @@ -222,7 +229,7 @@ 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)"); \ + return _("illegal boolean value, only 'yes|true|on' or 'no|false|off' allowed, ignored"); \ } while (0) const char * @@ -231,7 +238,7 @@ { char *end = line + strlen (line); - while (*end < ' ' && end >= line) + while (end >= line && *end < ' ') end--; *++end = 0; @@ -247,29 +254,42 @@ if (var[0] == '#') return 0; /* comment: ignore */ + if (!strcmp (var, "global")) + { + node = &conf.default_node; + return 0; + } + char *val = strtok (NULL, "\t\n\r ="); if (!val || val[0] == '#') - return _("no value given for variable. (ignored)"); + return _("no value given for variable, ignored"); - if (!strcmp (var, "on")) + else if (!strcmp (var, "on")) { - if (!::thisnode - || (val[0] == '!' && strcmp (val + 1, ::thisnode)) - || !strcmp (val, ::thisnode)) + if (::thisnode + && ((val[0] == '!' && strcmp (val + 1, ::thisnode)) + || !strcmp (val, ::thisnode))) return parse_line (strtok (NULL, "\n\r")); - else - return 0; + } + + else if (!strcmp (var, "include")) + { + char *fname = conf.config_filename (val); + parse_file (fname); + free (fname); } // truly global - if (!strcmp (var, "loglevel")) + else if (!strcmp (var, "loglevel")) { loglevel l = string_to_loglevel (val); if (l == L_NONE) - return _("unknown loglevel. (skipping)"); + return _("unknown loglevel, ignored"); } + else if (!strcmp (var, "serial")) + strncpy (conf.serial, val, sizeof (conf.serial)); else if (!strcmp (var, "ip-proto")) conf.ip_proto = atoi (val); else if (!strcmp (var, "icmp-type")) @@ -278,52 +298,34 @@ 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"); + + 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); - // per config + // per node else if (!strcmp (var, "node")) { - parse_argv (); - - conf.default_node.id++; - node = new conf_node (conf.default_node); - conf.nodes.push_back (node); - node->nodename = strdup (val); - - { - char *fname; - FILE *f; + node = conf.find_node (val); - 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); - } - - if (::thisnode && !strcmp (node->nodename, ::thisnode)) - conf.thisnode = node; + 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); @@ -339,6 +341,10 @@ 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")) @@ -385,6 +391,12 @@ 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 @@ -448,12 +460,14 @@ 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)"); + 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); + else if (!strcmp (var, "low-power")) + parse_bool (node->low_power, "low-power", true, false); // all these bool options really really cost a lot of executable size! else if (!strcmp (var, "enable-tcp")) { @@ -492,12 +506,13 @@ // unknown or misplaced else - return _("unknown configuration directive. (ignored)"); + return _("unknown configuration directive - ignored"); return 0; } -void conf_node::finalise () +void +conf_node::finalise () { if (max_queue < 1) { @@ -512,37 +527,30 @@ } } -void configuration_parser::parse_argv () +void +configuration_parser::parse_file (const char *fname) { - for (int i = 0; i < argc; ++i) + if (FILE *f = fopen (fname, "r")) { - char *v = argv [i]; - - if (!*v) - continue; - - char *enode = v; - - while (*enode != '.' && *enode > ' ' && *enode != '=' && *enode) - enode++; - - if (*enode != '.') - enode = 0; - - char *wnode = node == &conf.default_node - ? 0 - : node->nodename; + char line [2048]; + int lineno = 0; - if ((!wnode && !enode) - || (wnode && enode && !strncmp (wnode, v, enode - v))) + while (fgets (line, sizeof (line), f)) { - const char *warn = parse_line (enode ? enode + 1 : v); + lineno++; - if (warn) - slog (L_WARN, _("%s, while parsing command line option '%s'."), warn, v); + const char *warn = parse_line (line); - *v = 0; + if (warn) + slog (L_WARN, _("%s, at '%s', line %d."), warn, fname, lineno); } + + fclose (f); + } + else + { + slog (L_ERR, _("unable to read config file '%s': %s"), fname, strerror (errno)); + exit (EXIT_FAILURE); } } @@ -550,90 +558,157 @@ bool need_keys, int argc, char **argv) -: conf (conf),need_keys (need_keys), argc (argc), argv (argv) +: conf (conf), need_keys (need_keys), argc (argc), argv (argv) { char *fname; - FILE *f; conf.clear (); + node = &conf.default_node; asprintf (&fname, "%s/gvpe.conf", confbase); - f = fopen (fname, "r"); + parse_file (fname); + free (fname); - if (f) + fname = conf.config_filename (conf.prikeyfile, "hostkey"); + + if (FILE *f = fopen (fname, "r")) { - char line[16384]; - int lineno = 0; - node = &conf.default_node; + conf.rsa_key = RSA_new (); - while (fgets (line, sizeof (line), f)) + if (!PEM_read_RSAPrivateKey (f, &conf.rsa_key, NULL, NULL)) { - lineno++; - - const char *warn = parse_line (line); - - if (warn) - slog (L_WARN, _("%s, at '%s', line %d."), warn, fname, lineno); + 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 (EXIT_FAILURE); } - fclose (f); + require (RSA_blinding_on (conf.rsa_key, 0)); - parse_argv (); + fclose (f); } else { - slog (L_ERR, _("unable to read config file '%s': %s"), fname, strerror (errno)); - exit (EXIT_FAILURE); + if (need_keys) + { + 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.prikeyfile, "hostkey"); + fname = conf.config_filename (conf.pidfilename); + free (conf.pidfilename); conf.pidfilename = fname; - f = fopen (fname, "r"); - if (f) + for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i) { - conf.rsa_key = RSA_new (); + conf_node *node = *i; + char *fname; + FILE *f; - if (!PEM_read_RSAPrivateKey (f, &conf.rsa_key, NULL, NULL)) + asprintf (&fname, "%s/pubkey/%s", confbase, node->nodename); + + f = fopen (fname, "r"); + if (f) { - 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 (EXIT_FAILURE); + 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)); - require (RSA_blinding_on (conf.rsa_key, 0)); + if (need_keys) + exit (EXIT_FAILURE); + } - fclose (f); + free (fname); + + (*i)->finalise (); } - else + + if (::thisnode) { - slog (need_keys ? L_ERR : L_NOTICE, _("unable to open private rsa key file '%s': %s"), fname, strerror (errno)); + conf.thisnode = conf.find_node (::thisnode); if (need_keys) - exit (EXIT_FAILURE); + { + 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); + } + } } - if (need_keys && ::thisnode - && conf.rsa_key && conf.thisnode && 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 (); +} - free (fname); +void +configuration_parser::parse_argv () +{ + for (int i = 0; i < argc; ++i) + { + char *v = argv [i]; - for (configuration::node_vector::iterator i = conf.nodes.begin(); i != conf.nodes.end(); ++i) - (*i)->finalise (); + 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)) { @@ -646,6 +721,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")); @@ -659,8 +754,8 @@ 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 (); @@ -680,4 +775,3 @@ cleanup (); } -