Added .fwknoprc file creation and processing. This allows for saved default and named configuration profiles. Updated fwknop manpage to reflect the new capability. Also cleaned up messages (errors, info) from the program.
git-svn-id: file:///home/mbr/svn/fwknop/trunk@234 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
39
README
39
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
|
||||
|
||||
3
TODO
3
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
|
||||
|
||||
@@ -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 <ip addr>\n"
|
||||
"#SPOOF_USER <username>\n"
|
||||
"#SPOOF_SOURCE_IP <IPaddr>\n"
|
||||
"#TIME_OFFSET 0\n"
|
||||
"#USE_GPG N\n"
|
||||
"#GPG_HOMEDIR /path/to/.gnupg\n"
|
||||
"#GPG_SIGNER <signer ID>\n"
|
||||
"#GPG_RECIPIENT <recipient ID>\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"
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* 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},
|
||||
|
||||
144
client/fwknop.8
144
client/fwknop.8
@@ -2,12 +2,12 @@
|
||||
.\" Title: fwknop
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
|
||||
.\" 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<stanza name>\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)\&.
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,10 @@
|
||||
#define strncasecmp _strnicmp
|
||||
#define snprintf _snprintf
|
||||
#define unlink _unlink
|
||||
#define PATH_SEP "\\"
|
||||
#else
|
||||
#include <signal.h>
|
||||
#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***/
|
||||
|
||||
@@ -122,6 +122,18 @@ GENERAL OPTIONS
|
||||
invocation (if any). The previous arguments are parsed out of the
|
||||
'~/.fwknop.run' file.
|
||||
|
||||
*-n, --named-config*='<stanza name>'::
|
||||
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).
|
||||
|
||||
Reference in New Issue
Block a user