diff --git a/README b/README index 531527ad..21ec0bea 100644 --- a/README +++ b/README @@ -13,15 +13,20 @@ it is all about, go to http://www.cipherdyne.org/fwknop. CURRENT STATE ============= -At present, we have an initial implementation of the Firewall Knock -Operator library; `libfko'. This library provides the back-end functionality -for managing the Single Packet Authorization (SPA) data that fwknop -employs. +At present, we have an implementation of the Firewall Knock Operator +library; `libfko', as well as the fwknop client and server applications. +The library provides the API and back-end functionality for managing the +Single Packet Authorization (SPA) data that the other fwknop components +employ. It also can be used by other programs that need SPA functonality +(see the `perl' directory for the FKO perl module as an example). -This first version is planned to be compatible with fwknop version 1.9.x. +This first version of the C implementation is planned to be compatible +with legacy Perl-based fwknop version 1.9.x. However, it was decided to +start the version number at 2.0.0 to differentiate it from the current +Perl implementation. -BUILDING libfko +BUILDING fwknop =============== This distribution uses GNU autoconf for setting up the build. Please see the `INSTALL' file for the general basics on using autoconf. @@ -29,6 +34,10 @@ the `INSTALL' file for the general basics on using autoconf. There are some "configure" options that are specific to fwknop. They are (extracted from ./configure --help): + --disable-client Do not build the fwknop client component. The + default is to build the client. + --disable-server Do not build the fwknop server component. The + default is to build the server. --with-gpgme support for gpg encryption using libgpgme [default=check] --with-gpgme-prefix=PFX prefix where GPGME is installed (optional) @@ -44,6 +53,24 @@ There are some "configure" options that are specific to fwknop. They are path] +NOTE to those who may be migrating from the Perl version of fwknop +================================================================== +For those of you who are currently using the Perl version and plan to +migrate to this version, there are some things to be aware of: + + - Not all of the features and functionality of the Perl-based + fwknop were ported to this implementation. We felt it important + to keep the C version as lean and lightweight as possible. Most + of the omitted feature/functions (like email alerts) can be + accomplished through other means (i.e. use an external script + to monitor log files and alert based on appropriate log messages). + + - There are some diffences in the fwknop configuration and access + file directives and values. Some of these are fairly subtle. You + should pay careful attention to the documentation and comments in + those files. + + NOTE FOR DEVELOPERS =================== If you are pulling this distribution from Subversion, you will need to diff --git a/TODO b/TODO index 4b983d9d..d73d2413 100644 --- a/TODO +++ b/TODO @@ -10,7 +10,6 @@ To whom it may concern, this is -*- outline -*- mode. * The fwknopd server: ** Sniffer support to acquire SPA packet data ala the fwknopd Perl server: -*** Packets acquired via a file (supports the ulogd pcap writer). ** SPA packet decryption: *** Add support for ipfw and pf support eventually. ** Test on embedded platforms - especially OpenWRT on a Linksys router. @@ -30,7 +29,7 @@ To whom it may concern, this is -*- outline -*- mode. *** PHP module wrapping libfko. -Copyright 2009 - Damien Stuart +Copyright 2009-2010 - Damien Stuart This file is free software; as a special exception the author gives unlimited permission to copy and/or distribute it, with or without diff --git a/client/config_init.c b/client/config_init.c index df1e3633..fcb8562a 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -29,6 +29,44 @@ #include "utils.h" #include "ctype.h" +/* Convert a digest_type string to its intger value. +*/ +static int +digest_strtoint(char *dt_str) +{ + if(strcasecmp(dt_str, "md5") == 0) + return(FKO_DIGEST_MD5); + else if(strcasecmp(dt_str, "sha1") == 0) + return(FKO_DIGEST_SHA1); + else if(strcasecmp(dt_str, "sha256") == 0) + return(FKO_DIGEST_SHA256); + else if(strcasecmp(dt_str, "sha384") == 0) + return(FKO_DIGEST_SHA384); + else if(strcasecmp(dt_str, "sha512") == 0) + return(FKO_DIGEST_SHA512); + else + return(-1); +} + +/* Convert a protocol string to its intger value. +*/ +static int +proto_strtoint(char *pr_str) +{ + if (strcasecmp(optarg, "udp") == 0) + return(FKO_PROTO_UDP); + else if (strcasecmp(optarg, "tcpraw") == 0) + return(FKO_PROTO_TCP_RAW); + else if (strcasecmp(optarg, "tcp") == 0) + return(FKO_PROTO_TCP); + else if (strcasecmp(optarg, "icmp") == 0) + return(FKO_PROTO_ICMP); + else if (strcasecmp(optarg, "http") == 0) + return(FKO_PROTO_HTTP); + else + return(-1); +} + /* Parse any time offset from the command line */ static int @@ -61,14 +99,14 @@ parse_time_offset(char *offset_str) offset_digits[j] = '\0'; if (j < 1) { - fprintf(stderr, "[*] Invalid time offset: %s", offset_str); + fprintf(stderr, "Invalid time offset: %s", offset_str); exit(EXIT_FAILURE); } offset = atoi(offset_digits); if (offset < 0) { - fprintf(stderr, "[*] Invalid time offset: %s", offset_str); + fprintf(stderr, "Invalid time offset: %s", offset_str); exit(EXIT_FAILURE); } @@ -79,6 +117,393 @@ parse_time_offset(char *offset_str) return offset; } +static int +create_fwknoprc(char *rcfile) +{ + FILE *rc; + int res; + + fprintf(stderr, "Creating initial rc file: %s.\n", rcfile); + + if ((rc = fopen(rcfile, "w")) == NULL) + { + fprintf(stderr, "Unable to create rc file: %s: %s\n", + rcfile, strerror(errno)); + return(-1); + } + + fprintf(rc, + "# .fwknoprc\n" + "##############################################################################\n" + "#\n" + "# Firewall Knock Operator (fwknop) client rc file.\n" + "#\n" + "# This file contains user-specific fwknop client configuration default\n" + "# and named parameter sets for specific invocations of the fwknop client.\n" + "#\n" + "# Each section (or stanza) is identified and started by a line in this\n" + "# file that contains a single identifier surrounded by square brackets.\n" + "#\n" + "# The parameters within the stanza typicaly match corresponding client \n" + "# command-line parameters.\n" + "#\n" + "# The first one should always be `[default]' as it defines the global\n" + "# default settings for the user. These override the program defaults\n" + "# for these parameter. If a named stanza is used, its entries will\n" + "# override any of the default. Command-line options will trump them\n" + "# all.\n" + "#\n" + "# Subsequent stanzas will have only the overriding and destination\n" + "# specific parameters.\n" + "#\n" + "# Lines starting with `#' and empty lines are ignored.\n" + "#\n" + "# See the fwknop.8 man page for a complete list of valid parameters\n" + "# and thier values.\n" + "#\n" + "##############################################################################\n" + "#\n" + "# We start with the 'default' stanza. Uncomment and edit for your\n" + "# preferences. The client will use its build-in default for those items\n" + "# that are commented out.\n" + "#\n" + "[default]\n" + "\n" + "#DIGEST_TYPE sha256\n" + "#FW_TIMEOUT 30\n" + "#SPA_SERVER_PORT 62201\n" + "#SPA_SERVER_PROTO udp\n" + "#ALLOW_IP \n" + "#SPOOF_USER \n" + "#SPOOF_SOURCE_IP \n" + "#TIME_OFFSET 0\n" + "#USE_GPG N\n" + "#GPG_HOMEDIR /path/to/.gnupg\n" + "#GPG_SIGNER \n" + "#GPG_RECIPIENT \n" + "\n" + "# User-provided named stanzas:\n" + "\n" + "# Example for a destination server of 192.168.1.20 to open access to \n" + "# SSH for an IP that is resoved exteranlly, and one with a nat request\n" + "# for a specific source IP that maps port 8088 on the server\n" + "# to port 88 on 192.168.1.55 with timeout.\n" + "#\n" + "#[myssh]\n" + "#SPA_SERVER 192.168.1.20\n" + "#ACCESS tcp/22\n" + "#RESOLVE_IP_HTTP Y\n" + "#\n" + "#[mynatreq]\n" + "#SERVER 192.168.1.20\n" + "#ACCESS tcp/8088\n" + "#ALLOW_IP 10.21.2.6\n" + "#NAT_ACCESS 192.168.1.55,88\n" + "#CLIENT_TIMEOUT 60\n" + "#\n" + "\n" + "###EOF###\n" + ); + + return(0); +} + +static int +parse_rc_param(fko_cli_options_t *options, char *var, char * val) +{ + int tmpint; + + /* Digest Type */ + if(CONF_VAR_IS(var, "DIGEST_TYPE")) + { + tmpint = digest_strtoint(val); + if(tmpint < 0) + return(-1); + else + options->digest_type = tmpint; + } + /* Server protocol */ + else if(CONF_VAR_IS(var, "SPA_SERVER_PROTO")) + { + tmpint = proto_strtoint(val); + if(tmpint < 0) + return(-1); + else + options->spa_proto = tmpint; + } + /* Server port */ + else if(CONF_VAR_IS(var, "SPA_SERVER_PORT")) + { + tmpint = atoi(val); + if(tmpint < 0 || tmpint > 65535) + return(-1); + else + options->spa_dst_port = tmpint; + } + /* Source port */ + else if(CONF_VAR_IS(var, "SPA_SOURCE_PORT")) + { + tmpint = atoi(val); + if(tmpint < 0 || tmpint > 65535) + return(-1); + else + options->spa_src_port = tmpint; + } + /* Firewall rule timeout */ + else if(CONF_VAR_IS(var, "FW_TIMEOUT")) + { + tmpint = atoi(val); + if(tmpint < 0) + return(-1); + else + options->fw_timeout = tmpint; + } + /* Allow IP */ + else if(CONF_VAR_IS(var, "ALLOW_IP")) + { + /* use source, resolve, or an actual IP + */ + if(strcasecmp(val, "source") == 0) + strlcpy(options->allow_ip_str, "0.0.0.0", 8); + else if(strcasecmp(val, "resolve") == 0) + options->resolve_ip_http = 1; + else /* Assume IP address */ + strlcpy(options->allow_ip_str, val, MAX_IP_STR_LEN); + } + /* Time Offset */ + else if(CONF_VAR_IS(var, "TIME_OFFSET")) + { + if(val[0] == '-') + { + val++; + options->time_offset_minus = parse_time_offset(val); + } + else + options->time_offset_plus = parse_time_offset(val); + } + /* Use GPG ? */ + else if(CONF_VAR_IS(var, "USE_GPG")) + { + if(val[0] == 'y' || val[0] == 'Y') + options->use_gpg = 1; + } + /* GPG Recipient */ + else if(CONF_VAR_IS(var, "GPG_RECIPIENT")) + { + strlcpy(options->gpg_recipient_key, val, MAX_GPG_KEY_ID); + } + /* GPG Signer */ + else if(CONF_VAR_IS(var, "GPG_SIGNER")) + { + strlcpy(options->gpg_signer_key, val, MAX_GPG_KEY_ID); + } + /* GPG Homedir */ + else if(CONF_VAR_IS(var, "GPG_HOMEDIR")) + { + strlcpy(options->gpg_home_dir, val, MAX_PATH_LEN); + } + /* Spoof User */ + else if(CONF_VAR_IS(var, "SPOOF_USER")) + { + strlcpy(options->spoof_user, val, MAX_USERNAME_LEN); + } + /* Spoof Source IP */ + else if(CONF_VAR_IS(var, "SPOOF_SOURCE_IP")) + { + strlcpy(options->spoof_ip_src_str, val, MAX_IP_STR_LEN); + } + /* ACCESS request */ + else if(CONF_VAR_IS(var, "ACCESS")) + { + strlcpy(options->access_str, val, MAX_LINE_LEN); + } + /* SPA Server (destination) */ + else if(CONF_VAR_IS(var, "SPA_SERVER")) + { + strlcpy(options->spa_server_str, val, MAX_SERVER_STR_LEN); + } + /* Rand port ? */ + else if(CONF_VAR_IS(var, "RAND_PORT")) + { + if(val[0] == 'y' || val[0] == 'Y') + options->rand_port = 1; + } + /* Key file */ + else if(CONF_VAR_IS(var, "KEY_FILE")) + { + strlcpy(options->get_key_file, val, MAX_PATH_LEN); + } + /* NAT Access Request */ + else if(CONF_VAR_IS(var, "NAT_ACCESS")) + { + strlcpy(options->nat_access_str, val, MAX_PATH_LEN); + } + /* HTTP User Agent */ + else if(CONF_VAR_IS(var, "HTTP_USER_AGENT")) + { + strlcpy(options->http_user_agent, val, HTTP_MAX_USER_AGENT_LEN); + } + /* NAT Local ? */ + else if(CONF_VAR_IS(var, "NAT_LOCAL")) + { + if(val[0] == 'y' || val[0] == 'Y') + options->nat_local = 1; + } + /* NAT rand port ? */ + else if(CONF_VAR_IS(var, "NAT_RAND_PORT")) + { + if(val[0] == 'y' || val[0] == 'Y') + options->nat_rand_port = 1; + } + /* NAT port */ + else if(CONF_VAR_IS(var, "NAT_PORT")) + { + tmpint = atoi(val); + if(tmpint < 0 || tmpint > 65535) + return(-1); + else + options->nat_port = tmpint; + } + + return(0); +} + +/* Process (create if necessary) the users ~/.fwknoprc file. +*/ +static void +process_rc(fko_cli_options_t *options) +{ + FILE *rc; + int tmpint, line_num = 0; + char rcfile[MAX_PATH_LEN]; + char line[MAX_LINE_LEN]; + char curr_stanza[MAX_LINE_LEN] = {0}; + char var[MAX_LINE_LEN] = {0}; + char val[MAX_LINE_LEN] = {0}; + + char *ndx, *emark, *homedir = getenv("HOME"); + + if(homedir == NULL) + { + fprintf(stderr, "Warning: Unable to determine HOME directory.\n" + " No .fwknoprc file processed.\n"); + return; + } + + strlcpy(rcfile, homedir, MAX_PATH_LEN); + strlcat(rcfile, PATH_SEP); + strlcat(rcfile, ".fwknoprc"); + + /* Open the rc file for reading, if it does not exist, then create + * an initial .fwknoprc file with defaults and go on. + */ + if ((rc = fopen(rcfile, "r")) == NULL) + { + if(errno == ENOENT) + { + if(create_fwknoprc(rcfile) != 0) + return; + } + else + fprintf(stderr, "Unable to open rc file: %s: %s\n", + rcfile, strerror(errno)); + + return; + } + + /* Read in and parse the rc file parameters. + */ + while ((fgets(line, MAX_LINE_LEN, rc)) != NULL) + { + line_num++; + line[MAX_LINE_LEN-1] = '\0'; + + ndx = line; + + /* Skip any leading whitespace. + */ + while(isspace(*ndx)) + ndx++; + + /* Get past comments and empty lines (note: we only look at the + * first character. + */ + if(IS_EMPTY_LINE(line[0])) + continue; + + if(*ndx == '[') + { + ndx++; + emark = strchr(ndx, ']'); + if(emark == NULL) + { + fprintf(stderr, "Unterminated stanza line: '%s'. Skipping.\n", + line); + continue; + } + + *emark = '\0'; + + strlcpy(curr_stanza, ndx, MAX_LINE_LEN); + + if(options->verbose > 3) + fprintf(stderr, + "RC FILE: %s, LINE: %s\tSTANZA: %s:\n", + rcfile, line, curr_stanza + ); + + continue; + } + + if(sscanf(line, "%s %[^;\n\r#]", var, val) != 2) + { + fprintf(stderr, + "*Invalid entry in %s at line %i.\n - '%s'", + rcfile, line_num, line + ); + continue; + } + + /* Remove any colon that may be on the end of the var + */ + if((ndx = strrchr(var, ':')) != NULL) + *ndx = '\0'; + + if(options->verbose > 3) + fprintf(stderr, + "RC FILE: %s, LINE: %s\tVar: %s, Val: '%s'\n", + rcfile, line, var, val + ); + + /* We do not proceed with parsing until we know we are in + * a stanza. + */ + if(strlen(curr_stanza) < 1) + continue; + + /* Process the values. We assume we will see the default stanza + * first, then if a named-stanza is specified, we process its + * entries as well. + */ + if(strcasecmp(curr_stanza, "default") == 0 || (options->use_rc_stanza[0] != '\0' + && strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0)) + { + if(parse_rc_param(options, var, val) < 0) + fprintf(stderr, "Parameter error in %s, line %i: var=%s, val=%i\n", + rcfile, line_num, var, val); + } + else if(options->use_rc_stanza[0] != '\0' + && strncasecmp(curr_stanza, options->use_rc_stanza, MAX_LINE_LEN)==0) + { + options->got_named_stanza = 1; + if(parse_rc_param(options, var, val) < 0) + fprintf(stderr, "Parameter error in %s, stanza: %s, line %i: var=%s, val=%i\n", + rcfile, curr_stanza, line_num, var, val); + } + + } /* end while fgets rc */ +} + /* Sanity and bounds checks for the various options. */ static void @@ -92,19 +517,27 @@ validate_options(fko_cli_options_t *options) && !options->show_last_command && !options->run_last_command) { - if (options->spa_server_str[0] == 0x0) + if(options->use_rc_stanza[0] != 0x0 && options->got_named_stanza == 0) { - fprintf(stderr, - "[*] Must use --destination unless --test mode is used\n"); - exit(EXIT_FAILURE); - } - if (!options->resolve_ip_http && options->allow_ip_str[0] == 0x0) - { - fprintf(stderr, - "[*] Must use one of [-s|-R|-a] to specify IP for SPA access.\n"); + fprintf(stderr, "Named configuration stanza: [%s] was not found.\n", + options->use_rc_stanza); + exit(EXIT_FAILURE); } + if (options->spa_server_str[0] == 0x0) + { + fprintf(stderr, + "Must use --destination unless --test mode is used\n"); + exit(EXIT_FAILURE); + } + + if (!options->resolve_ip_http && options->allow_ip_str[0] == 0x0) + { + fprintf(stderr, + "Must use one of [-s|-R|-a] to specify IP for SPA access.\n"); + exit(EXIT_FAILURE); + } } if(options->resolve_ip_http || options->spa_proto == FKO_PROTO_HTTP) @@ -115,7 +548,7 @@ validate_options(fko_cli_options_t *options) if(options->http_proxy[0] != 0x0 && options->spa_proto != FKO_PROTO_HTTP) { fprintf(stderr, - "[*] Cannot set --http-proxy with a non-HTTP protocol.\n"); + "Cannot set --http-proxy with a non-HTTP protocol.\n"); exit(EXIT_FAILURE); } @@ -127,7 +560,7 @@ validate_options(fko_cli_options_t *options) || strlen(options->gpg_recipient_key) == 0) { fprintf(stderr, - "[*] Must specify --gpg-recipient-key when GPG is used.\n"); + "Must specify --gpg-recipient-key when GPG is used.\n"); exit(EXIT_FAILURE); } } @@ -154,6 +587,33 @@ config_init(fko_cli_options_t *options, int argc, char **argv) options->spa_dst_port = FKO_DEFAULT_PORT; options->fw_timeout = -1; + /* First pass over cmd_line args to see if a named-stanza in the + * rc file is used. + */ + while ((cmd_arg = getopt_long(argc, argv, + GETOPTS_OPTION_STRING, cmd_opts, &index)) != -1) { + switch(cmd_arg) { + case 'h': + usage(); + exit(EXIT_SUCCESS); + case 'n': + options->no_save_args = 1; + strlcpy(options->use_rc_stanza, optarg, MAX_LINE_LEN); + break; + case 'v': + options->verbose++; + break; + } + } + + /* First process the .fwknoprc file. + */ + process_rc(options); + + /* Reset the options index so we can run through them again. + */ + optind = 0; + while ((cmd_arg = getopt_long(argc, argv, GETOPTS_OPTION_STRING, cmd_opts, &index)) != -1) { @@ -179,7 +639,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) case 'f': options->fw_timeout = atoi(optarg); if (options->fw_timeout < 0) { - fprintf(stderr, "[*] --fw-timeout must be >= 0\n"); + fprintf(stderr, "--fw-timeout must be >= 0\n"); exit(EXIT_FAILURE); } break; @@ -202,48 +662,34 @@ config_init(fko_cli_options_t *options, int argc, char **argv) break; case 'm': case FKO_DIGEST_NAME: - if(strncasecmp(optarg, "md5", 3) == 0) - options->digest_type = FKO_DIGEST_MD5; - else if(strncasecmp(optarg, "sha1", 4) == 0) - options->digest_type = FKO_DIGEST_SHA1; - else if(strncasecmp(optarg, "sha256", 6) == 0) - options->digest_type = FKO_DIGEST_SHA256; - else if(strncasecmp(optarg, "sha384", 6) == 0) - options->digest_type = FKO_DIGEST_SHA384; - else if(strncasecmp(optarg, "sha512", 6) == 0) - options->digest_type = FKO_DIGEST_SHA512; - else + if((options->digest_type = digest_strtoint(optarg)) < 0) { fprintf(stderr, "* Invalid digest type: %s\n", optarg); exit(EXIT_FAILURE); } break; + case 'NO_SAVE_ARGS': + options->no_save_args = 1; + break; case 'n': - options->no_save = 1; + /* We already handled this earlier, so we do nothing here + */ break; case 'N': strlcpy(options->nat_access_str, optarg, MAX_LINE_LEN); break; case 'p': options->spa_dst_port = atoi(optarg); - if (options->spa_dst_port < 0 || options->spa_dst_port > 65535) { - fprintf(stderr, "[*] Unrecognized port: %s\n", optarg); + if (options->spa_dst_port < 0 || options->spa_dst_port > 65535) + { + fprintf(stderr, "Unrecognized port: %s\n", optarg); exit(EXIT_FAILURE); } break; case 'P': - if (strncmp(optarg, "udp", strlen("udp")) == 0) - options->spa_proto = FKO_PROTO_UDP; - else if (strncmp(optarg, "tcpraw", strlen("tcpraw")) == 0) - options->spa_proto = FKO_PROTO_TCP_RAW; - else if (strncmp(optarg, "tcp", strlen("tcp")) == 0) - options->spa_proto = FKO_PROTO_TCP; - else if (strncmp(optarg, "icmp", strlen("icmp")) == 0) - options->spa_proto = FKO_PROTO_ICMP; - else if (strncmp(optarg, "http", strlen("http")) == 0) - options->spa_proto = FKO_PROTO_HTTP; - else { - fprintf(stderr, "[*] Unrecognized protocol: %s\n", optarg); + if((options->spa_proto = proto_strtoint(optarg)) < 0) + { + fprintf(stderr, "Unrecognized protocol: %s\n", optarg); exit(EXIT_FAILURE); } break; @@ -264,8 +710,9 @@ config_init(fko_cli_options_t *options, int argc, char **argv) break; case 'S': options->spa_src_port = atoi(optarg); - if (options->spa_src_port < 0 || options->spa_src_port > 65535) { - fprintf(stderr, "[*] Unrecognized port: %s\n", optarg); + if (options->spa_src_port < 0 || options->spa_src_port > 65535) + { + fprintf(stderr, "Unrecognized port: %s\n", optarg); exit(EXIT_FAILURE); } break; @@ -279,7 +726,8 @@ config_init(fko_cli_options_t *options, int argc, char **argv) strlcpy(options->spoof_user, optarg, MAX_USERNAME_LEN); break; case 'v': - options->verbose = 1; + /* Handled earlier. + */ break; case 'V': options->version = 1; @@ -308,8 +756,9 @@ config_init(fko_cli_options_t *options, int argc, char **argv) break; case NAT_PORT: options->nat_port = atoi(optarg); - if (options->nat_port < 0 || options->nat_port > 65535) { - fprintf(stderr, "[*] Unrecognized port: %s\n", optarg); + if (options->nat_port < 0 || options->nat_port > 65535) + { + fprintf(stderr, "Unrecognized port: %s\n", optarg); exit(EXIT_FAILURE); } break; @@ -353,6 +802,9 @@ usage(void) " -C, --server-cmd Specify a command that the fwknop server will\n" " execute on behalf of the fwknop client..\n" " -D, --destination Specify the IP address of the fwknop server.\n" + " -n, --named-config Specify an named configuration stanza in the\n" + " '$HOME/.fwknoprc' file to provide some of all\n" + " of the configuration parameters.\n" " -N, --nat-access Gain NAT access to an internal service\n" " protected by the fwknop server.\n" " -p, --server-port Set the destination port for outgoing SPA\n" diff --git a/client/config_init.h b/client/config_init.h index ca794fcd..490199f9 100644 --- a/client/config_init.h +++ b/client/config_init.h @@ -29,6 +29,10 @@ #include #include +/* String compare macro. +*/ +#define CONF_VAR_IS(n, v) (strcmp(n, v) == 0) + /* Long options values (for those without a short option). */ enum { @@ -51,7 +55,7 @@ enum { /* Our getopt_long options string. */ -#define GETOPTS_OPTION_STRING "a:A:bB:C:D:f:gG:hH:lm:nN:p:P:Q:rRsS:Tu:U:vV" +#define GETOPTS_OPTION_STRING "a:A:bB:C:D:f:gG:hH:lm:n:N:p:P:Q:rRsS:Tu:U:vV" /* Our program command-line options... */ @@ -76,6 +80,7 @@ static struct option cmd_opts[] = {"http-proxy", 1, NULL, 'H'}, {"last-cmd", 0, NULL, 'l'}, {"nat-access", 1, NULL, 'N'}, + {"named-config", 1, NULL, 'n'}, {"nat-local", 0, NULL, NAT_LOCAL}, {"nat-port", 1, NULL, NAT_PORT}, {"nat-rand-port", 0, NULL, NAT_RAND_PORT}, diff --git a/client/fwknop.8 b/client/fwknop.8 index bc60c8d6..e1fdefa8 100644 --- a/client/fwknop.8 +++ b/client/fwknop.8 @@ -2,12 +2,12 @@ .\" Title: fwknop .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets v1.75.2 -.\" Date: 06/27/2010 +.\" Date: 07/05/2010 .\" Manual: Fwknop Client .\" Source: Fwknop Client .\" Language: English .\" -.TH "FWKNOP" "8" "06/27/2010" "Fwknop Client" "Fwknop Client" +.TH "FWKNOP" "8" "07/05/2010" "Fwknop Client" "Fwknop Client" .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- @@ -126,6 +126,13 @@ with the command\-line arguments from the previous invocation (if any)\&. The pr file\&. .RE .PP +\fB\-n, \-\-named\-config\fR=\fI\fR +.RS 4 +The +\fBfwknop\fR +client program can use parameters specified in it rc file, \(oq`\&.fwknoprc\'\' which is found in the user\'s home directory\&. If *fwknop* does not detect the $HOME/\&.fwknoprc file, it will create it\&. The \'\&.fwkoprc\' file contains a default configuration area or \'stanza\' which holds global configuration directives that override the program defaults\&. You can edit this file and create additonal \'named stanzas\' that can be specified with this (\'\-n\') option\&. Parameters defined in the named stanzas will override any matching \'default\' stanza directives\&. See the section: FWKNOPRC FILE below for a list of the valid configuration directives in the ``\&.fwknoprc\(cq\' file\&. +.RE +.PP \fB\-\-show\-last\fR .RS 4 Display the last command\-line arguments used by @@ -408,6 +415,139 @@ Specify the GnuPG key ID, e\&.g\&. \(oq`+ABCD1234+\'\' (see the output of ``gpg \fBfwknopd\fR daemon on the remote server to authenticate who created the SPA message\&. .RE +.SH "FWKNOPRC FILE" +.sp +The \(lq\&.fwknoprc\(rq file is used to set various parameters to override default program parameters at runtime\&. It also allows for additional named configuration \fIstanzas\fR for setting program parameters for a particular invocation\&. +.sp +The \fBfwkop\fR client will create this file if it does not exist in the user\(cqs home directory\&. This initial version has some sample directives that are commented out\&. It is up to the user to edit this file to meet their needs\&. +.sp +There are directives to match most of the command\-line parameters \fBfwknop\fR supports\&. Here is the current list of each directive along with a brief description and (if applicable) it matching command\-line option: +.PP +\fBDIGEST_TYPE\fR +.RS 4 +Set the SPA message digest type (\'\-m, \-\-digest\-type)\&. +.RE +.PP +\fBSPA_SERVER_PROTO\fR +.RS 4 +Set the protocol to use for sending the SPA packet (\fI\-P, \-\-server\-proto\fR)\&. +.RE +.PP +\fBSPA_SERVER\fR +.RS 4 +Specify the IP or hostname of the destination (\fBfwknopd\fR) server (\'\-D, \-\-destination)\&. +.RE +.PP +\fBSPA_SERVER_PORT\fR +.RS 4 +Set the server port to use for sending the SPA packet (\fI\-p, \-\-server\-port\fR)\&. +.RE +.PP +\fBSPA_SOURCE_PORT\fR +.RS 4 +Set the source port to use for sending the SPA packet (\fI\-S, \-\-source\-port\fR)\&. +.RE +.PP +\fBFW_TIMEOUT\fR +.RS 4 +Set the firewall rule timeout value (\fI\-f, \-\-fw\-timeout\fR)\&. +.RE +.PP +\fBALLOW_IP\fR +.RS 4 +Specify the address to allow within the SPA data\&. Note: This parameter covers the +\fI\-a\fR, +\fI\-s\fR, and +\fI\-R\fR +command\-line options\&. You can specify an IP address (the +\fI\-a\fR +option), specify the word "source" to tell the +\fBfwknopd\fR +server to accept the source IP of the packet as the IP to allow (the +\fI\-s\fR +option), or use the word "resolve" to have +\fBfwknop\fR +resolve the external network IP via HTTP request (the +\fI\-R\fR +option)\&. +.RE +.PP +\fBTIME_OFFSET\fR +.RS 4 +Set a value to apply to the timestamp in the SPA packet\&. This can be either a positive or negative value (\fI\-\-time\-offset\-plus/minus\fR)\&. +.RE +.PP +\fBUSE_GPG\fR +.RS 4 +Set to +\fIY\fR +to specify the use of GPG for encryption (\fI\-\-gpg\-encryption\fR)\&. +.RE +.PP +\fBGPG_SIGNER\fR +.RS 4 +Specify the GPG key name or ID for signing the GPG\-encrypted SPA data (\fI\-\-gpg\-signer\-key\fR)\&. +.RE +.PP +\fBGPG_RECIPIENT\fR +.RS 4 +Specify the GPG key name or ID for the recipient of the GPG\-encrypted SPA data (\fI\-\-gpg\-recipient\-key\fR)\&. +.RE +.PP +\fBGPG_HOMEDIR\fR +.RS 4 +Specify the GPG home directory (\fI\-\-gpg\-home\-dir\fR)\&. +.RE +.PP +\fBSPOOF_USER\fR +.RS 4 +Set the username in the SPA data to the specified value (\fI\-U, \-\-spoof\-user\fR)\&. +.RE +.PP +\fBSPOOF_SOURCE_IP\fR +.RS 4 +Set the source IP of the outgoing SPA packet to the specified value (\fI\-Q, \-\-spoof\-source\fR)\&. +.RE +.PP +\fBACCESS\fR +.RS 4 +Set the one or more protocol/ports to open on the firewall (\fI\-A, \-\-access\fR)\&. +.RE +.PP +\fBRAND_PORT\fR +.RS 4 +Send the SPA packet over a randomly assigned port (\fI\-r, \-\-rand\-port\fR)\&. +.RE +.PP +\fBKEY_FILE\fR +.RS 4 +Load an encryption key/password from a file (\fI\-G, \-\-get\-key\fR)\&. +.RE +.PP +\fBHTTP_USER_AGENT\fR +.RS 4 +Set the HTTP User\-Agent for resolving the external IP via \-R, or for sending SPA packets over HTTP (\fI\-u, \-\-user\-agent\fR)\&. +.RE +.PP +\fBNAT_ACCESS\fR +.RS 4 +Gain NAT access to an internal service protected by the fwknop server (\fI\-N, \-\-nat\-access\fR)\&. +.RE +.PP +\fBNAT_LOCAL\fR +.RS 4 +Access a local service via a forwarded port on the fwknopd server system (\fI\-\-nat\-local\fR)\&. +.RE +.PP +\fBNAT_PORT\fR +.RS 4 +Specify the port to forward to access a service via NAT (\fI\-\-nat\-port\fR)\&. +.RE +.PP +\fBNAT_RAND_PORT\fR +.RS 4 +Have the fwknop client assign a random port for NAT access (\fI\-\-nat\-rand\-port\fR)\&. +.RE .SH "ENVIRONMENT" .sp \fBGPG_AGENT_INFO\fR (only used in \fB\-\-gpg\-agent\fR mode)\&. diff --git a/client/fwknop.c b/client/fwknop.c index 15bf1e04..6c3ef290 100644 --- a/client/fwknop.c +++ b/client/fwknop.c @@ -58,6 +58,7 @@ main(int argc, char **argv) /* Handle command line */ config_init(&options, argc, argv); + /* Handle options that don't require a libfko context */ if(options.run_last_command) @@ -81,7 +82,7 @@ main(int argc, char **argv) if (options.version) { fko_get_version(ctx, &version); - fprintf(stdout, "[+] fwknop client %s, FKO protocol version %s\n", + fprintf(stdout, "fwknop client %s, FKO protocol version %s\n", MY_VERSION, version); return(EXIT_SUCCESS); @@ -274,13 +275,13 @@ main(int argc, char **argv) res = send_spa_packet(ctx, &options); if(res < 0) { - fprintf(stderr, "[*] send_spa_packet: packet not sent.\n"); + fprintf(stderr, "send_spa_packet: packet not sent.\n"); return(EXIT_FAILURE); } else { if(options.verbose) - fprintf(stderr, "[+] send_spa_packet: bytes sent: %i\n", res); + fprintf(stderr, "send_spa_packet: bytes sent: %i\n", res); } /* Run through a decode cycle in test mode (--DSS XXX: This test/decode @@ -346,7 +347,7 @@ main(int argc, char **argv) * an unrecoverable error), but print the error string for debugging purposes. */ fprintf(stderr, "GPG ERR: %s\n%s\n", fko_gpg_errstr(ctx2), - "[*] No access to recipient private key?\n"); + "No access to recipient private key?\n"); return(EXIT_SUCCESS); } @@ -422,7 +423,7 @@ get_rand_port(fko_ctx_t ctx) static void dump_transmit_options(fko_cli_options_t *options) { - printf("[+] Generating SPA packet:\n protocol: "); + printf("Generating SPA packet:\n protocol: "); print_proto(options->spa_proto), printf("\n port: %d\n", options->spa_dst_port); return; @@ -524,20 +525,20 @@ show_last_command(void) /* Not sure what the right thing is here on Win32, just exit * for now. */ - fprintf(stderr, "[*] --show-last not implemented on Win32 yet."); + fprintf(stderr, "--show-last not implemented on Win32 yet."); exit(EXIT_FAILURE); #endif if (get_save_file(args_save_file)) { if ((args_file_ptr = fopen(args_save_file, "r")) == NULL) { - fprintf(stderr, "[*] Could not open args file: %s\n", + fprintf(stderr, "Could not open args file: %s\n", args_save_file); exit(EXIT_FAILURE); } if ((fgets(args_str, MAX_LINE_LEN, args_file_ptr)) != NULL) { - printf("[+] Last fwknop client command line: %s", args_str); + printf("Last fwknop client command line: %s", args_str); } else { - printf("[-] Could not read line from file: %s\n", args_save_file); + printf("Could not read line from file: %s\n", args_save_file); } fclose(args_file_ptr); } @@ -573,7 +574,7 @@ run_last_args(fko_cli_options_t *options) { if ((args_file_ptr = fopen(args_save_file, "r")) == NULL) { - fprintf(stderr, "[*] Could not open args file: %s\n", + fprintf(stderr, "Could not open args file: %s\n", args_save_file); exit(EXIT_FAILURE); } @@ -581,7 +582,7 @@ run_last_args(fko_cli_options_t *options) { args_str[MAX_LINE_LEN-1] = '\0'; if (options->verbose) - printf("[+] Executing: %s\n", args_str); + printf("Executing: %s\n", args_str); for (i=0; i < (int)strlen(args_str); i++) { if (!isspace(args_str[i])) @@ -595,7 +596,7 @@ run_last_args(fko_cli_options_t *options) argv_new[argc_new] = malloc(strlen(arg_tmp)+1); if (argv_new[argc_new] == NULL) { - fprintf(stderr, "[*] malloc failure for cmd line arg.\n"); + fprintf(stderr, "malloc failure for cmd line arg.\n"); exit(EXIT_FAILURE); } strcpy(argv_new[argc_new], arg_tmp); @@ -636,14 +637,14 @@ save_args(int argc, char **argv) if (get_save_file(args_save_file)) { if ((args_file_ptr = fopen(args_save_file, "w")) == NULL) { - fprintf(stderr, "[*] Could not open args file: %s\n", + fprintf(stderr, "Could not open args file: %s\n", args_save_file); exit(EXIT_FAILURE); } for (i=0; i < argc; i++) { args_str_len += strlen(argv[i]); if (args_str_len >= MAX_PATH_LEN) { - fprintf(stderr, "[*] argument string too long, exiting.\n"); + fprintf(stderr, "argument string too long, exiting.\n"); exit(EXIT_FAILURE); } strlcat(args_str, argv[i], MAX_PATH_LEN); @@ -739,7 +740,7 @@ get_user_pw(fko_cli_options_t *options, int crypt_op) */ if (pw_ptr == NULL) { - fprintf(stderr, "[*] Received no password data, exiting.\n"); + fprintf(stderr, "Received no password data, exiting.\n"); exit(EXIT_FAILURE); } @@ -750,7 +751,7 @@ get_user_pw(fko_cli_options_t *options, int crypt_op) */ void errmsg(char *msg, int err) { - fprintf(stderr, "[*] %s: %s: Error %i - %s\n", + fprintf(stderr, "%s: %s: Error %i - %s\n", MY_NAME, msg, err, fko_errstr(err)); } diff --git a/client/fwknop_common.h b/client/fwknop_common.h index c55f5ac6..6677c68a 100644 --- a/client/fwknop_common.h +++ b/client/fwknop_common.h @@ -113,7 +113,6 @@ typedef struct fko_cli_options /* Various command-line flags */ unsigned char verbose; /* --verbose mode */ unsigned char version; /* --version */ - unsigned char no_save; unsigned char test; unsigned char use_gpg; unsigned char use_gpg_agent; @@ -121,6 +120,9 @@ typedef struct fko_cli_options int time_offset_minus; int fw_timeout; + char use_rc_stanza[MAX_LINE_LEN]; + unsigned char got_named_stanza; + //char config_file[MAX_PATH_LEN]; } fko_cli_options_t; diff --git a/client/getpasswd.c b/client/getpasswd.c index ef9470b1..cf903629 100644 --- a/client/getpasswd.c +++ b/client/getpasswd.c @@ -148,7 +148,7 @@ getpasswd_file(const char *pw_file, const char *server_str) if ((pwfile_ptr = fopen(pw_file, "r")) == NULL) { - fprintf(stderr, "[*] Could not open config file: %s\n", pw_file); + fprintf(stderr, "Could not open config file: %s\n", pw_file); exit(1); } @@ -202,7 +202,7 @@ getpasswd_file(const char *pw_file, const char *server_str) fclose(pwfile_ptr); if (pwbuf[0] == '\0') { - fprintf(stderr, "[*] Could not get password for IP: %s from: %s\n", + fprintf(stderr, "Could not get password for IP: %s from: %s\n", server_str, pw_file); exit(1); } diff --git a/client/http_resolve_host.c b/client/http_resolve_host.c index 5eb00354..a7435210 100644 --- a/client/http_resolve_host.c +++ b/client/http_resolve_host.c @@ -57,7 +57,7 @@ resolve_ip_http(fko_cli_options_t *options) res = WSAStartup( MAKEWORD(1,1), &wsa_data ); if( res != 0 ) { - fprintf(stderr, "[*] Winsock initialization error %d\n", res ); + fprintf(stderr, "Winsock initialization error %d\n", res ); return(-1); } #endif @@ -82,7 +82,7 @@ resolve_ip_http(fko_cli_options_t *options) error = getaddrinfo(HTTP_RESOLVE_HOST, "80", &hints, &result); if (error != 0) { - fprintf(stderr, "[*] error in getaddrinfo: %s\n", gai_strerror(error)); + fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error)); return(-1); } @@ -103,7 +103,7 @@ resolve_ip_http(fko_cli_options_t *options) } if (rp == NULL) { - perror("[*] resolve_ip_http: Could not create socket: "); + perror("resolve_ip_http: Could not create socket: "); return(-1); } @@ -113,7 +113,7 @@ resolve_ip_http(fko_cli_options_t *options) if(res < 0) { - perror("[*] resolve_ip_http: write error: "); + perror("resolve_ip_http: write error: "); } else if(res != http_buf_len) { @@ -137,7 +137,7 @@ resolve_ip_http(fko_cli_options_t *options) ndx = strstr(http_response, "\r\n\r\n"); if(ndx == NULL) { - fprintf(stderr, "[*] Did not find the end of HTTP header.\n"); + fprintf(stderr, "Did not find the end of HTTP header.\n"); return(-1); } ndx += 4; @@ -167,14 +167,14 @@ resolve_ip_http(fko_cli_options_t *options) strlcpy(options->allow_ip_str, ndx, MAX_IP_STR_LEN); if(options->verbose) - printf("[+] Resolved external IP (via http://%s%s) as: %s\n", + printf("Resolved external IP (via http://%s%s) as: %s\n", HTTP_RESOLVE_HOST, HTTP_RESOLVE_URL, options->allow_ip_str); return(0); } else { - fprintf(stderr, "[*] Invalid IP (%s) in HTTP response.\n", ndx); + fprintf(stderr, "Invalid IP (%s) in HTTP response.\n", ndx); return(-1); } } diff --git a/client/spa_comm.c b/client/spa_comm.c index 0692d3fe..52f30e05 100644 --- a/client/spa_comm.c +++ b/client/spa_comm.c @@ -82,7 +82,7 @@ send_spa_packet_tcp_or_udp(char *spa_data, int sd_len, fko_cli_options_t *option if (options->test) { fprintf(stderr, - "[+] test mode enabled, SPA packet not actually sent.\n"); + "test mode enabled, SPA packet not actually sent.\n"); return res; } @@ -112,7 +112,7 @@ send_spa_packet_tcp_or_udp(char *spa_data, int sd_len, fko_cli_options_t *option if (error != 0) { - fprintf(stderr, "[*] error in getaddrinfo: %s\n", gai_strerror(error)); + fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error)); exit(EXIT_FAILURE); } @@ -133,7 +133,7 @@ send_spa_packet_tcp_or_udp(char *spa_data, int sd_len, fko_cli_options_t *option } if (rp == NULL) { - perror("[*] send_spa_packet_tcp_or_udp: Could not create socket: "); + perror("send_spa_packet_tcp_or_udp: Could not create socket: "); exit(EXIT_FAILURE); } @@ -143,7 +143,7 @@ send_spa_packet_tcp_or_udp(char *spa_data, int sd_len, fko_cli_options_t *option if(res < 0) { - perror("[*] send_spa_packet_tcp_or_udp: write error: "); + perror("send_spa_packet_tcp_or_udp: write error: "); } else if(res != sd_len) { @@ -170,7 +170,7 @@ send_spa_packet_tcp_raw(char *spa_data, int sd_len, struct sockaddr_in *saddr, { #ifdef WIN32 fprintf(stderr, - "[*] send_spa_packet_tcp_raw: raw packets are not yet supported.\n"); + "send_spa_packet_tcp_raw: raw packets are not yet supported.\n"); return(-1); #else int sock, res = 0; @@ -189,14 +189,14 @@ send_spa_packet_tcp_raw(char *spa_data, int sd_len, struct sockaddr_in *saddr, if (options->test) { fprintf(stderr, - "[+] test mode enabled, SPA packet not actually sent.\n"); + "test mode enabled, SPA packet not actually sent.\n"); return res; } sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW); if (sock < 0) { - perror("[*] send_spa_packet_tcp_raw: create socket: "); + perror("send_spa_packet_tcp_raw: create socket: "); return(sock); } @@ -250,14 +250,14 @@ send_spa_packet_tcp_raw(char *spa_data, int sd_len, struct sockaddr_in *saddr, * doesn't try to insert its own header into the packet. */ if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0) - perror("[*] send_spa_packet_tcp_raw: setsockopt HDRINCL: "); + perror("send_spa_packet_tcp_raw: setsockopt HDRINCL: "); res = sendto (sock, pkt_data, iph->tot_len, 0, (struct sockaddr *)daddr, sizeof(*daddr)); if(res < 0) { - perror("[*] send_spa_packet_tcp_raw: sendto error: "); + perror("send_spa_packet_tcp_raw: sendto error: "); } else if(res != sd_len + hdrlen) /* account for the header ?*/ { @@ -281,7 +281,7 @@ send_spa_packet_icmp(char *spa_data, int sd_len, struct sockaddr_in *saddr, struct sockaddr_in *daddr, fko_cli_options_t *options) { #ifdef WIN32 - fprintf(stderr, "[*] send_spa_packet_icmp: raw packets are not yet supported.\n"); + fprintf(stderr, "send_spa_packet_icmp: raw packets are not yet supported.\n"); return(-1); #else int res = 0, sock; @@ -300,7 +300,7 @@ send_spa_packet_icmp(char *spa_data, int sd_len, struct sockaddr_in *saddr, if (options->test) { fprintf(stderr, - "[+] test mode enabled, SPA packet not actually sent.\n"); + "test mode enabled, SPA packet not actually sent.\n"); return res; } @@ -308,7 +308,7 @@ send_spa_packet_icmp(char *spa_data, int sd_len, struct sockaddr_in *saddr, if (sock < 0) { - perror("[*] send_spa_packet_icmp: create socket: "); + perror("send_spa_packet_icmp: create socket: "); return(sock); } @@ -348,14 +348,14 @@ send_spa_packet_icmp(char *spa_data, int sd_len, struct sockaddr_in *saddr, * doesn't try to insert its own header into the packet. */ if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, so_val, sizeof(one)) < 0) - perror("[*] send_spa_packet_icmp: setsockopt HDRINCL: "); + perror("send_spa_packet_icmp: setsockopt HDRINCL: "); res = sendto (sock, pkt_data, iph->tot_len, 0, (struct sockaddr *)daddr, sizeof(*daddr)); if(res < 0) { - perror("[*] send_spa_packet_icmp: sendto error: "); + perror("send_spa_packet_icmp: sendto error: "); } else if(res != sd_len + hdrlen) /* account for icmp header */ { @@ -451,7 +451,7 @@ send_spa_packet_http(char *spa_data, int sd_len, fko_cli_options_t *options) fprintf(stderr, "%s\n", http_buf); fprintf(stderr, - "[+] Test mode enabled, SPA packet not actually sent.\n"); + "Test mode enabled, SPA packet not actually sent.\n"); return 0; } @@ -493,7 +493,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) res = WSAStartup( MAKEWORD(1,1), &wsa_data ); if( res != 0 ) { - fprintf(stderr, "[*] Winsock initialization error %d\n", res ); + fprintf(stderr, "Winsock initialization error %d\n", res ); return(-1); } #endif @@ -531,7 +531,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) if (saddr.sin_addr.s_addr == -1) { - fprintf(stderr, "[*] Could not set source IP.\n"); + fprintf(stderr, "Could not set source IP.\n"); exit(EXIT_FAILURE); } @@ -542,7 +542,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) if (daddr.sin_addr.s_addr == -1) { - fprintf(stderr, "[*] Could not set destination IP.\n"); + fprintf(stderr, "Could not set destination IP.\n"); exit(EXIT_FAILURE); } @@ -558,7 +558,7 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options) else { /* --DSS XXX: What to we really want to do here? */ - fprintf(stderr, "[*] %i is not a valid or supported protocol.\n", + fprintf(stderr, "%i is not a valid or supported protocol.\n", options->spa_proto); res = -1; } diff --git a/common/common.h b/common/common.h index a81842a4..ea9ed682 100644 --- a/common/common.h +++ b/common/common.h @@ -56,8 +56,10 @@ #define strncasecmp _strnicmp #define snprintf _snprintf #define unlink _unlink + #define PATH_SEP "\\" #else #include + #define PATH_SEP "/" #endif #include "fko.h" @@ -92,6 +94,23 @@ enum { #define MAX_GPG_KEY_ID 128 #define MAX_USERNAME_LEN 30 +/* Some convenience macros */ + +/* Characters allowed between a config parameter and its value. +*/ +#define IS_CONFIG_PARAM_DELIMITER(x) (x == ' ' || x == '\t' || x == '='); + +/* End of line characters. +*/ +#define IS_LINE_END(x) (x == '\n' || x == '\r' || x == ';'); + +/* Characters in the first position of a line that make it considered + * empty or otherwise non-interesting (like a comment). +*/ +#define IS_EMPTY_LINE(x) ( \ + x == '#' || x == '\n' || x == '\r' || x == ';' || x == '\0' \ +) + #endif /* _COMMON_H */ /***EOF***/ diff --git a/doc/fwknop.man.asciidoc b/doc/fwknop.man.asciidoc index 06748909..eff79b89 100644 --- a/doc/fwknop.man.asciidoc +++ b/doc/fwknop.man.asciidoc @@ -122,6 +122,18 @@ GENERAL OPTIONS invocation (if any). The previous arguments are parsed out of the '~/.fwknop.run' file. +*-n, --named-config*='':: + The *fwknop* client program can use parameters specified in it rc file, + ``.fwknoprc'' which is found in the user's home directory. If *fwknop* + does not detect the $HOME/.fwknoprc file, it will create it. The + '.fwkoprc' file contains a default configuration area or 'stanza' + which holds global configuration directives that override the program + defaults. You can edit this file and create additonal 'named stanzas' + that can be specified with this ('-n') option. Parameters defined + in the named stanzas will override any matching 'default' stanza + directives. See the section: FWKNOPRC FILE below for a list of the + valid configuration directives in the ``.fwknoprc'' file. + *--show-last*:: Display the last command-line arguments used by *fwknop*. @@ -321,6 +333,102 @@ GPG-RELATED OPTIONS the SPA message. +FWKNOPRC FILE +------------- +The ``.fwknoprc'' file is used to set various parameters to override default +program parameters at runtime. It also allows for additional named configuration +'stanzas' for setting program parameters for a particular invocation. + +The *fwkop* client will create this file if it does not exist in the user's +home directory. This initial version has some sample directives that are +commented out. It is up to the user to edit this file to meet their needs. + +There are directives to match most of the command-line parameters *fwknop* +supports. Here is the current list of each directive along with a brief +description and (if applicable) it matching command-line option: + +*DIGEST_TYPE*:: + Set the SPA message digest type ('-m, --digest-type). + +*SPA_SERVER_PROTO*:: + Set the protocol to use for sending the SPA packet ('-P, --server-proto'). + +*SPA_SERVER*:: + Specify the IP or hostname of the destination (*fwknopd*) server + ('-D, --destination). + +*SPA_SERVER_PORT*:: + Set the server port to use for sending the SPA packet ('-p, --server-port'). + +*SPA_SOURCE_PORT*:: + Set the source port to use for sending the SPA packet ('-S, --source-port'). + +*FW_TIMEOUT*:: + Set the firewall rule timeout value ('-f, --fw-timeout'). + +*ALLOW_IP*:: + Specify the address to allow within the SPA data. Note: This parameter + covers the '-a', '-s', and '-R' command-line options. You can specify + an IP address (the '-a' option), specify the word "source" to tell the + *fwknopd* server to accept the source IP of the packet as the IP to + allow (the '-s' option), or use the word "resolve" to have *fwknop* + resolve the external network IP via HTTP request (the '-R' option). + +*TIME_OFFSET*:: + Set a value to apply to the timestamp in the SPA packet. This can + be either a positive or negative value ('--time-offset-plus/minus'). + +*USE_GPG*:: + Set to 'Y' to specify the use of GPG for encryption ('--gpg-encryption'). + +*GPG_SIGNER*:: + Specify the GPG key name or ID for signing the GPG-encrypted SPA data + ('--gpg-signer-key'). + +*GPG_RECIPIENT*:: + Specify the GPG key name or ID for the recipient of the GPG-encrypted SPA + data ('--gpg-recipient-key'). + +*GPG_HOMEDIR*:: + Specify the GPG home directory ('--gpg-home-dir'). + +*SPOOF_USER*:: + Set the username in the SPA data to the specified value ('-U, + --spoof-user'). + +*SPOOF_SOURCE_IP*:: + Set the source IP of the outgoing SPA packet to the specified value + ('-Q, --spoof-source'). + +*ACCESS*:: + Set the one or more protocol/ports to open on the firewall ('-A, --access'). + +*RAND_PORT*:: + Send the SPA packet over a randomly assigned port ('-r, --rand-port'). + +*KEY_FILE*:: + Load an encryption key/password from a file ('-G, --get-key'). + +*HTTP_USER_AGENT*:: + Set the HTTP User-Agent for resolving the external IP via -R, or for + sending SPA packets over HTTP ('-u, --user-agent'). + +*NAT_ACCESS*:: + Gain NAT access to an internal service protected by the fwknop server + ('-N, --nat-access'). + +*NAT_LOCAL*:: + Access a local service via a forwarded port on the fwknopd server + system ('--nat-local'). + +*NAT_PORT*:: + Specify the port to forward to access a service via NAT ('--nat-port'). + +*NAT_RAND_PORT*:: + Have the fwknop client assign a random port for NAT access + ('--nat-rand-port'). + + ENVIRONMENT ----------- *GPG_AGENT_INFO* (only used in *--gpg-agent* mode).