diff --git a/doc/Advanced.md b/doc/Advanced.md index 28d1f03..e118cb8 100644 --- a/doc/Advanced.md +++ b/doc/Advanced.md @@ -1,6 +1,10 @@ # Advanced Configuration +## Configuration Files + +Read about [Configuration Files](ConfigurationFiles.md) as they might come in handy – especially, but not limited to, if edges or supernodes shall be run as a service (see below) or in case of bulk automated parameter generation for mass deployment. + ## Running edge as a Service edge can also be run as a service instead of cli: diff --git a/doc/ConfigurationFiles.md b/doc/ConfigurationFiles.md new file mode 100644 index 0000000..62f5d2f --- /dev/null +++ b/doc/ConfigurationFiles.md @@ -0,0 +1,73 @@ +# Configuration Files + +To help deployment of locally different configurations, n2n supports the use of configuration files for `edge` and `supernode`. + +They are plain text files and contain the desired command line options, **one per line**. + +The exemplary command line + +```bash +sudo edge -c mynetwork -k mysecretpass -a 192.168.100.1 -f -l supernode.ntop.org:7777 +``` + +translates into the following `edge.conf` file: + +``` +-c mynetwork +-k mysecretpass +-a 192.168.100.1 +-f +-l supernode.ntop.org:7777 +``` + +which can be loaded by + +``` +sudo ./edge edge.conf +``` + +The `.conf` file syntax also allows `=` between parameter and its option: + +``` +-c=mynetwork +-k=mysecretpass +-a=192.168.100.1 +-f +-l=supernode.ntop.org:7777 +``` + +When used with `=`, there is no whitespace allowed between parameter, delimter (`=`), and option. So, do **not** put `-c = mynetwork` – it is required to be `-c=mynetwork`. + +Comment lines starting with a hash '#' are ignored. + +``` +# automated edge configuration +# created by bot7 +# on April 31, 2038 – 1800Z +-c mynetwork +-k mysecretpass +-a 192.168.100.1 +-f +# --- supernode section --- +-l supernode.ntop.org:7777 +``` + +Long options can be used as well. Please note the double minus/dash character `--`, just like on command line: + +``` +# automated edge configuration +# created by bot7 +# on April 31, 2038 – 1800Z +--community mynetwork +-k mysecretpass +-a 192.168.100.1 +-f +# --- supernode section --- +-l supernode.ntop.org:7777 +``` + +If using a configuration file, its filename needs to be supplied as first parameter to `edge` or `supernode`. If required, additional command line parameters can be supplied afterwards: + +``` +sudo edge edge.conf -A5 +``` \ No newline at end of file diff --git a/src/edge.c b/src/edge.c index 14e1707..1735bb1 100644 --- a/src/edge.c +++ b/src/edge.c @@ -1,5 +1,5 @@ /** - * (C) 2007-20 - ntop.org and contributors + * (C) 2007-21 - ntop.org and contributors * * 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 @@ -525,14 +525,14 @@ static int setOption (int optkey, char *optargument, n2n_tuntap_priv_config_t *e static const struct option long_options[] = { - { "community", required_argument, NULL, 'c' }, + { "community", required_argument, NULL, 'c' }, { "supernode-list", required_argument, NULL, 'l' }, - { "tap-device", required_argument, NULL, 'd' }, - { "euid", required_argument, NULL, 'u' }, - { "egid", required_argument, NULL, 'g' }, - { "help" , no_argument, NULL, 'h' }, - { "verbose", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } + { "tap-device", required_argument, NULL, 'd' }, + { "euid", required_argument, NULL, 'u' }, + { "egid", required_argument, NULL, 'g' }, + { "help" , no_argument, NULL, 'h' }, + { "verbose", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } }; /* *************************************************** */ @@ -549,8 +549,10 @@ static int loadFromCLI (int argc, char *argv[], n2n_edge_conf_t *conf, n2n_tunta #endif , long_options, NULL)) != '?') { + if(c == 255) break; setOption(c, optarg, ec, conf); + } return 0; @@ -579,10 +581,11 @@ static char *trim (char *s) { /* parse the configuration file */ static int loadFromFile (const char *path, n2n_edge_conf_t *conf, n2n_tuntap_priv_config_t *ec) { - char buffer[4096], *line, *key, *value; - u_int line_len, opt_name_len; + char buffer[4096], *line; + char *line_vec[3]; + int tmp; + FILE *fd; - const struct option *opt; fd = fopen(path, "r"); @@ -591,71 +594,29 @@ static int loadFromFile (const char *path, n2n_edge_conf_t *conf, n2n_tuntap_pri return -1; } + // we mess around with optind, better save it + tmp = optind; + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { line = trim(line); - value = NULL; - if((line_len = strlen(line)) < 2 || line[0] == '#') + if(strlen(line) < 2 || line[0] == '#') continue; - if(!strncmp(line, "--", 2)) { /* long opt */ - key = &line[2], line_len -= 2; - - opt = long_options; - while(opt->name != NULL) { - opt_name_len = strlen(opt->name); - - if(!strncmp(key, opt->name, opt_name_len) - && (line_len <= opt_name_len - || key[opt_name_len] == '\0' - || key[opt_name_len] == ' ' - || key[opt_name_len] == '=')) { - if(line_len > opt_name_len) key[opt_name_len] = '\0'; - if(line_len > opt_name_len + 1) value = trim(&key[opt_name_len + 1]); - - // traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value); - setOption(opt->val, value, ec, conf); - break; - } - - opt++; - } - } else if(line[0] == '-') { /* short opt */ - char *equal; - - key = &line[1], line_len--; - - equal = strchr(line, '='); - - if(equal) { - equal[0] = '\0'; - value = &equal[1]; - - if((value[0] == '\0') && (key[1] != '\0')) - value = &key[1]; - } else { - value = NULL; - - /* Adding an exception for -A_ -z_ which can come - without '=' and even without any further data */ - - if(key[0] == 'z') { - if(key[1]) value = &key[1]; - key = "z"; - } else if(key[0] == 'A') { - if(key[1]) value = &key[1]; - key = "A"; - } - } - // traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value); - setOption(key[0], value, ec, conf); - } else { - traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line); - continue; - } + // executable, cannot be omitted, content can be anything + line_vec[0] = line; + // first token, e.g. `-p` or `-A3', eventually followed by a whitespace or '=' delimiter + line_vec[1] = strtok(line, "\t ="); + // separate parameter option, if present + line_vec[2] = strtok(NULL, "\t "); + // not to duplicate the option parser code, call loadFromCLI and pretend we have no option read yet + optind = 1; + // if second token present (optional argument, not part of first), then announce 3 vector members + loadFromCLI(line_vec[2] ? 3 : 2, line_vec, conf, ec); } fclose(fd); + optind = tmp; return 0; } @@ -783,8 +744,9 @@ int main (int argc, char* argv[]) { } else if(argc > 1) rc = loadFromCLI(argc, argv, &conf, &ec); else + #ifdef WIN32 - /* Load from current directory */ + // load from current directory rc = loadFromFile("edge.conf", &conf, &ec); #else rc = -1; diff --git a/src/sn.c b/src/sn.c index b189397..0adcd7b 100644 --- a/src/sn.c +++ b/src/sn.c @@ -1,5 +1,5 @@ /** - * (C) 2007-20 - ntop.org and contributors + * (C) 2007-21 - ntop.org and contributors * * 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 @@ -455,10 +455,11 @@ static char *trim (char *s) { /* parse the configuration file */ static int loadFromFile (const char *path, n2n_sn_t *sss) { - char buffer[4096], *line, *key, *value; - u_int line_len, opt_name_len; + char buffer[4096], *line; + char *line_vec[3]; + int tmp; + FILE *fd; - const struct option *opt; fd = fopen(path, "r"); @@ -467,55 +468,31 @@ static int loadFromFile (const char *path, n2n_sn_t *sss) { return -1; } - while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { + // we mess around with optind, better save it + tmp = optind; + while((line = fgets(buffer, sizeof(buffer), fd)) != NULL) { line = trim(line); - value = NULL; - if((line_len = strlen(line)) < 2 || line[0] == '#') { + if(strlen(line) < 2 || line[0] == '#') { continue; } - if(!strncmp(line, "--", 2)) { /* long opt */ - key = &line[2], line_len -= 2; - - opt = long_options; - while(opt->name != NULL) { - opt_name_len = strlen(opt->name); - - if(!strncmp(key, opt->name, opt_name_len) - && (line_len <= opt_name_len - || key[opt_name_len] == '\0' - || key[opt_name_len] == ' ' - || key[opt_name_len] == '=')) { - if(line_len > opt_name_len) { - key[opt_name_len] = '\0'; - } - if(line_len > opt_name_len + 1) { - value = trim(&key[opt_name_len + 1]); - } - - // traceEvent(TRACE_NORMAL, "long key: %s value: %s", key, value); - setOption(opt->val, value, sss); - break; - } - - opt++; - } - } else if(line[0] == '-') { /* short opt */ - key = &line[1], line_len--; - if(line_len > 1) key[1] = '\0'; - if(line_len > 2) value = trim(&key[2]); - - // traceEvent(TRACE_NORMAL, "key: %c value: %s", key[0], value); - setOption(key[0], value, sss); - } else { - traceEvent(TRACE_WARNING, "Skipping unrecognized line: %s", line); - continue; - } + // executable, cannot be omitted, content can be anything + line_vec[0] = line; + // first token, e.g. `-p`, eventually followed by a whitespace or '=' delimiter + line_vec[1] = strtok(line, "\t ="); + // separate parameter option, if present + line_vec[2] = strtok(NULL, "\t "); + + // not to duplicate the option parser code, call loadFromCLI and pretend we have no option read yet + optind = 1; + // if separate second token present (optional argument, not part of first), then announce 3 vector members + loadFromCLI(line_vec[2] ? 3 : 2, line_vec, sss); } fclose(fd); + optind = tmp; return 0; } @@ -624,9 +601,9 @@ int main (int argc, char * const argv[]) { } else if(argc > 1) { rc = loadFromCLI(argc, argv, &sss_node); } else - + #ifdef WIN32 - /* Load from current directory */ + // load from current directory rc = loadFromFile("supernode.conf", &sss_node); #else rc = -1; @@ -636,7 +613,6 @@ int main (int argc, char * const argv[]) { help(); } - #if defined(N2N_HAVE_DAEMON) if(sss_node.daemon) { setUseSyslog(1); /* traceEvent output now goes to syslog. */