Major rearrangement. Renamed directories: "fko" to "lib", "src" to "client". Added "common" and "server" directories. Setup autoconf to allow disabling the server and/or client builds.

git-svn-id: file:///home/mbr/svn/fwknop/trunk@127 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
Damien Stuart
2009-08-09 15:43:16 +00:00
parent 078661e355
commit 53b7fae8bb
56 changed files with 327 additions and 222 deletions

8
client/Makefile.am Normal file
View File

@@ -0,0 +1,8 @@
bin_PROGRAMS = fwknop
fwknop_SOURCES = fwknop.c fwknop.h config_init.c config_init.h \
fwknop_common.h spa_comm.c spa_comm.h utils.c utils.h \
http_resolve_host.c getpasswd.c getpasswd.h
fwknop_LDADD = $(top_builddir)/lib/libfko.la
fwknop_CPPFLAGS = -I $(top_srcdir)/lib -I $(top_srcdir)/common

527
client/config_init.c Normal file
View File

@@ -0,0 +1,527 @@
/*
******************************************************************************
*
* File: config_init.c
*
* Author: Damien Stuart
*
* Purpose: Command-line and config file processing for fwknop client.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
******************************************************************************
*/
#include "fwknop_common.h"
#include "config_init.h"
#include "getopt.h"
#include "utils.h"
#include "ctype.h"
/* Routine to extract the configuration value from a line in the config
* file.
*/
int
get_char_val(const char *var_name, char *dest, char *lptr)
{
int i, var_char_ctr = 0;
char *tmp_ptr;
tmp_ptr = lptr;
/* var_name is guaranteed to be NULL-terminated.
*/
for (i=0; i < (int)strlen(var_name); i++)
if (tmp_ptr[i] != var_name[i])
return 0;
tmp_ptr += i;
/* First char after varName better be a space or tab or '='.
*/
if (*tmp_ptr != ' ' && *tmp_ptr != '\t' && *tmp_ptr != '=')
return 0;
/* Walk past the delimiter.
*/
while (*tmp_ptr == ' ' || *tmp_ptr == '\t' || *tmp_ptr == '=')
tmp_ptr++;
while (var_char_ctr < MAX_LINE_LEN && tmp_ptr[var_char_ctr] != '\n'
&& tmp_ptr[var_char_ctr] != '\0')
var_char_ctr++;
if (tmp_ptr[var_char_ctr] != '\n' || var_char_ctr >= MAX_LINE_LEN)
return 0;
strncpy(dest, tmp_ptr, var_char_ctr);
dest[var_char_ctr] = '\0';
return 1;
}
/* Parse any time offset from the command line
*/
static int
parse_time_offset(char *offset_str)
{
int i, j;
int offset = 0;
int offset_type = TIME_OFFSET_SECONDS;
int os_len = strlen(offset_str);
char offset_digits[MAX_TIME_STR_LEN];
j=0;
for (i=0; i < os_len; i++) {
if (isdigit(offset_str[i])) {
offset_digits[j] = offset_str[i];
j++;
} else if (offset_str[i] == 'm' || offset_str[i] == 'M') {
offset_type = TIME_OFFSET_MINUTES;
break;
} else if (offset_str[i] == 'h' || offset_str[i] == 'H') {
offset_type = TIME_OFFSET_HOURS;
break;
} else if (offset_str[i] == 'd' || offset_str[i] == 'D') {
offset_type = TIME_OFFSET_DAYS;
break;
}
}
offset_digits[j] = '\0';
if (j < 1) {
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);
exit(EXIT_FAILURE);
}
switch (offset_type) {
case TIME_OFFSET_MINUTES:
offset *= 60;
break;
case TIME_OFFSET_HOURS:
offset *= 60 * 60;
break;
case TIME_OFFSET_DAYS:
offset *= 60 * 60 * 24;
break;
}
return offset;
}
/* Parse the config file...
*/
static void
parse_config_file(fko_cli_options_t *options, struct opts_track* ot)
{
FILE *cfile_ptr;
unsigned int numLines = 0;
char conf_line_buf[MAX_LINE_LEN] = {0};
char tmp_char_buf[MAX_LINE_LEN] = {0};
char *lptr;
struct stat st;
/* First see if the config file exists. If it doesn't, and was
* specified via command-line, then error out. Otherwise, complain
* and go on with program defaults.
*/
if(stat(options->config_file, &st) != 0)
{
if(ot->got_config_file)
{
fprintf(stderr, "[*] Could not open config file: %s\n",
options->config_file);
exit(EXIT_FAILURE);
}
fprintf(stderr,
"** Config file was not found. Attempting to continue with defaults...\n"
);
return;
}
if ((cfile_ptr = fopen(options->config_file, "r")) == NULL)
{
fprintf(stderr, "[*] Could not open config file: %s\n",
options->config_file);
exit(EXIT_FAILURE);
}
while ((fgets(conf_line_buf, MAX_LINE_LEN, cfile_ptr)) != NULL)
{
numLines++;
conf_line_buf[MAX_LINE_LEN-1] = '\0';
lptr = conf_line_buf;
memset(tmp_char_buf, 0x0, MAX_LINE_LEN);
while (*lptr == ' ' || *lptr == '\t' || *lptr == '=')
lptr++;
/* Get past comments and empty lines.
*/
if (*lptr == '#' || *lptr == '\n' || *lptr == '\r' || *lptr == '\0' || *lptr == ';')
continue;
/*--DSS TODO: Figure out what to put here
if (ot->got_device == 0 || options->interface.name[0] == '\0')
get_char_val("XXXX", options->interface.name, lptr);
if (ot->got_snaplen == 0 && get_char_val("SNAPLEN", tmp_char_buf, lptr))
options->snapLen = atoi(tmp_char_buf);
*/
}
fclose(cfile_ptr);
return;
}
/* Sanity and bounds checks for the various options.
*/
static void
validate_options(fko_cli_options_t *options)
{
/* Gotta have a Destination unless we are just testing or getting the
* the version, and must use one of [-s|-R|-a].
*/
if(!options->test && !options->version && !options->show_last_command)
{
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)
if (options->http_user_agent[0] == '\0')
snprintf(options->http_user_agent, HTTP_MAX_USER_AGENT_LEN,
"%s%s", "Fwknop/", MY_VERSION);
/* If we are using gpg, we must at least have the recipient set.
*/
if(options->use_gpg)
{
if(options->gpg_recipient_key == NULL
|| strlen(options->gpg_recipient_key) == 0)
{
fprintf(stderr,
"[*] Must specify --gpg-recipient-key when GPG is used.\n");
exit(EXIT_FAILURE);
}
}
return;
}
/* Initialize program configuration via config file and/or command-line
* switches.
*/
void
config_init(fko_cli_options_t *options, int argc, char **argv)
{
int cmd_arg, index;
struct opts_track ot;
/* Zero out options and opts_track.
*/
memset(options, 0x00, sizeof(fko_cli_options_t));
memset(&ot, 0x00, sizeof(ot));
/* Establish a few defaults such as UDP/62201 for sending the SPA
* packet (can be changed with --server-proto/--server-port)
*/
options->spa_proto = FKO_DEFAULT_PROTO;
options->spa_dst_port = FKO_DEFAULT_PORT;
options->fw_timeout = -1;
while ((cmd_arg = getopt_long(argc, argv,
"a:A:bB:C:D:f:gG:hIm:nN:p:P:qQ:rRsS:Tu:U:vV", cmd_opts, &index)) != -1) {
switch(cmd_arg) {
case 'a':
strlcpy(options->allow_ip_str, optarg, MAX_IP_STR_LEN);
break;
case 'A':
strlcpy(options->access_str, optarg, MAX_LINE_LEN);
break;
case 'b':
options->save_packet_file_append = 1;
break;
case 'B':
strlcpy(options->save_packet_file, optarg, MAX_PATH_LEN);
break;
case 'C':
strlcpy(options->server_command, optarg, MAX_LINE_LEN);
break;
case 'D':
strlcpy(options->spa_server_str, optarg, MAX_SERVER_STR_LEN);
break;
case 'f':
options->fw_timeout = atoi(optarg);
if (options->fw_timeout < 0) {
fprintf(stderr, "[*] --fw-timeout must be >= 0\n");
exit(EXIT_FAILURE);
}
break;
case 'g':
case GPG_ENCRYPTION:
options->use_gpg = 1;
break;
case 'G':
strlcpy(options->get_key_file, optarg, MAX_PATH_LEN);
break;
case 'h':
usage();
exit(EXIT_SUCCESS);
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
{
fprintf(stderr, "* Invalid digest type: %s\n", optarg);
exit(EXIT_FAILURE);
}
break;
case 'n':
options->no_save = 1;
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);
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);
exit(EXIT_FAILURE);
}
break;
case 'q':
options->quiet = 1;
break;
case 'Q':
strlcpy(options->spoof_ip_src_str, optarg, MAX_IP_STR_LEN);
break;
case 'r':
options->rand_port = 1;
break;
case 'R':
options->resolve_ip_http = 1;
break;
case SHOW_LAST_ARGS:
options->show_last_command = 1;
break;
case 's':
strlcpy(options->allow_ip_str, "0.0.0.0", MAX_IP_STR_LEN);
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);
exit(EXIT_FAILURE);
}
break;
case 'T':
options->test = 1;
break;
case 'u':
strlcpy(options->http_user_agent, optarg, HTTP_MAX_USER_AGENT_LEN);
break;
case 'U':
strlcpy(options->spoof_user, optarg, MAX_USERNAME_LEN);
break;
case 'v':
options->verbose = 1;
break;
case 'V':
options->version = 1;
break;
case GPG_RECIP_KEY:
options->use_gpg = 1;
strlcpy(options->gpg_recipient_key, optarg, MAX_GPG_KEY_ID);
break;
case GPG_SIGNER_KEY:
options->use_gpg = 1;
strlcpy(options->gpg_signer_key, optarg, MAX_GPG_KEY_ID);
break;
case GPG_HOME_DIR:
options->use_gpg = 1;
strlcpy(options->gpg_home_dir, optarg, MAX_PATH_LEN);
break;
case GPG_AGENT:
options->use_gpg = 1;
options->use_gpg_agent = 1;
break;
case NAT_LOCAL:
options->nat_local = 1;
break;
case NAT_RAND_PORT:
options->nat_rand_port = 1;
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);
exit(EXIT_FAILURE);
}
break;
case TIME_OFFSET_PLUS:
options->time_offset_plus = parse_time_offset(optarg);
break;
case TIME_OFFSET_MINUS:
options->time_offset_minus = parse_time_offset(optarg);
break;
case NO_SAVE_ARGS:
options->no_save_args = 1;
break;
default:
usage();
exit(EXIT_FAILURE);
}
}
/* Parse configuration file to populate any params not already specified
* via command-line options
*/
//--DSS XXX: We will use this when we have a config file to use.
//parse_config_file(options, &ot);
/* Now that we have all of our options set, we can validate them.
*/
validate_options(options);
return;
}
/* Print usage message...
*/
void
usage(void)
{
fprintf(stderr, "\n%s client version %s\n%s\n\n", MY_NAME, MY_VERSION, MY_DESC);
fprintf(stderr,
"Usage: fwknop -A <port list> [-s|-R|-a] -D <spa_server> [options]\n\n"
" -h, --help - Print this usage message and exit.\n"
" -c, --config-file - Specify an alternate configuration file.\n"
" -A, --access - Provide a list of ports/protocols to open\n"
" on the server.\n"
" -B, --save-packet - Save the generated packet data to the\n"
" specified file.\n"
" -a, --allow-ip - Specify IP address to allow within the SPA\n"
" packet.\n"
" -D, --destination - Specify the IP address of the fwknop server.\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"
" packet.\n"
" -P, --server-proto - Set the protocol (udp, tcp, tcpraw, icmp) for\n"
" the outgoing SPA packet. Note: The 'tcpraw'\n"
" and 'icmp' modes use raw sockets and thus\n"
" require root access to run.\n"
" -s, --source-ip - Tell the fwknopd server to accept whatever\n"
" source IP the SPA packet has as the IP that\n"
" needs access (not recommended, and the\n"
" fwknopd server can ignore such requests).\n"
" -S, --source-port - Set the source port for outgoing SPA packet.\n"
" -Q, --spoof-source - Set the source IP for outgoing SPA packet.\n"
" -R, --resolve-ip-http - Resolve the external network IP by\n"
" connecting to the URL:\n"
" http://"
HTTP_RESOLVE_HOST
HTTP_RESOLVE_URL
"\n"
" -u, --user-agent - Set the HTTP User-Agent for resolving the\n"
" external IP via -R, or for sending SPA\n"
" packets over HTTP.\n"
" -U, --spoof-user - Set the username within outgoing SPA packet.\n"
" -q, --quiet - Perform fwknop functions quietly.\n"
" -G, --get-key - Load an encryption key/password from a file.\n"
" -r, --rand-port - Send the SPA packet over a randomly assigned\n"
" port (requires a broader pcap filter on the\n"
" server side than the default of udp 62201).\n"
" -T, --test - Build the SPA packet but do not send it over\n"
" the network.\n"
" -v, --verbose - Set verbose mode.\n"
" -V, --version - Print version number.\n"
" -m, --digest-type - Speciy the message digest algorithm to use.\n"
" (md5, sha1, or sha256 (default)).\n"
" -f, --fw-timeout - Specify SPA server firewall timeout from the\n"
" client side.\n"
" --gpg-encryption - Use GPG encyrption (default is Rijndael).\n"
" --gpg-recipient-key - Specify the recipient GPG key name or ID.\n"
" --gpg-signer-key - Specify the signer's GPG key name or ID.\n"
" --gpg-home-dir - Specify the GPG home directory.\n"
" --gpg-agent - Use GPG agent if available.\n"
" --nat-local - Access a local service via a forwarded port\n"
" on the fwknopd server system.\n"
" --nat-port - Specify the port to forward to access a\n"
" service via NAT.\n"
" --nat-rand-port - Have the fwknop client assign a random port\n"
" for NAT access.\n"
" --show-last - Show the last fwknop command line arguments.\n"
" --time-offset-plus - Add time to outgoing SPA packet timestamp.\n"
" --time-offset-minus - Subtract time from outgoing SPA packet\n"
" timestamp.\n"
"\n"
);
return;
}
/***EOF***/

115
client/config_init.h Normal file
View File

@@ -0,0 +1,115 @@
/*
******************************************************************************
*
* File: fwknop.h
*
* Author: Damien Stuart
*
* Purpose: Header file for fwknop config_init.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
******************************************************************************
*/
#ifndef CONFIG_INIT_H
#define CONFIG_INIT_H
#include <getopt.h>
#include <sys/stat.h>
/* Long options values (for those without a short option).
*/
enum {
FKO_DIGEST_NAME = 0x100,
NAT_LOCAL,
NAT_PORT,
NAT_RAND_PORT,
TIME_OFFSET_MINUS,
TIME_OFFSET_PLUS,
NO_SAVE_ARGS,
SHOW_LAST_ARGS,
/* Put GPG-related items below the following line */
GPG_ENCRYPTION = 0x200,
GPG_RECIP_KEY,
GPG_SIGNER_KEY,
GPG_HOME_DIR,
GPG_AGENT,
NOOP /* Just to be a marker for the end */
};
/* Our program command-line options...
*/
static struct option cmd_opts[] =
{
{"allow-ip", 1, NULL, 'a'},
{"access", 1, NULL, 'A'},
{"save-packet-append", 0, NULL, 'b'},
{"save-packet", 1, NULL, 'B'},
{"no-save", 0, NULL, NO_SAVE_ARGS},
{"server-command", 1, NULL, 'C'},
{"digest-type", 1, NULL, FKO_DIGEST_NAME},
{"destination", 1, NULL, 'D'},
{"fw-timeout", 1, NULL, 'f'},
{"gpg-encryption", 0, NULL, 'g'},
{"gpg-recipient-key", 1, NULL, GPG_RECIP_KEY },
{"gpg-signer-key", 1, NULL, GPG_SIGNER_KEY },
{"gpg-home-dir", 1, NULL, GPG_HOME_DIR },
{"gpg-agent", 0, NULL, GPG_AGENT },
{"get-key", 1, NULL, 'G'},
{"help", 0, NULL, 'h'},
{"no-save", 0, NULL, 'n'},
{"nat-access", 1, NULL, 'N'},
{"nat-local", 0, NULL, NAT_LOCAL},
{"nat-port", 1, NULL, NAT_PORT},
{"nat-rand-port", 0, NULL, NAT_RAND_PORT},
{"server-port", 1, NULL, 'p'},
{"server-proto", 1, NULL, 'P'},
{"quiet", 0, NULL, 'q'},
{"spoof-src", 1, NULL, 'Q'},
{"rand-port", 0, NULL, 'r'},
{"resolve-ip-http", 0, NULL, 'R'},
{"show-last", 0, NULL, SHOW_LAST_ARGS},
{"source-ip", 0, NULL, 's'},
{"source-port", 1, NULL, 'S'},
{"test", 0, NULL, 'T'},
{"time-offset-plus", 1, NULL, TIME_OFFSET_PLUS},
{"time-offset-minus", 1, NULL, TIME_OFFSET_MINUS},
{"user-agent", 1, NULL, 'u'},
{"spoof-user", 1, NULL, 'U'},
{"verbose", 0, NULL, 'v'},
{"version", 0, NULL, 'V'},
{0, 0, 0, 0}
};
/* Track config options set via command-line.
* --DSS: XXX: These will need to be reviewed...
*/
typedef struct opts_track {
unsigned int got_destination:1;
unsigned int got_server_port:1;
unsigned int got_server_proto:1;
unsigned int got_config_file:1;
unsigned int got_source_port:1;
unsigned int got_spoof_src:1;
} opts_track_t;
/* Function Prototypes
*/
void config_init(fko_cli_options_t *options, int argc, char **argv);
void usage(void);
#endif /* CONFIG_INIT_H */
/***EOF***/

721
client/fwknop.c Normal file
View File

@@ -0,0 +1,721 @@
/* $Id$
*****************************************************************************
*
* File: fwknop.c
*
* Author: Damien S. Stuart
*
* Purpose: An implementation of an fwknop client.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#include "fwknop.h"
#include "config_init.h"
#include "spa_comm.h"
#include "utils.h"
#include "getpasswd.h"
/* prototypes
*/
char* get_user_pw(fko_cli_options_t *options, int crypt_op);
static void display_ctx(fko_ctx_t ctx);
void errmsg(char *msg, int err);
static void show_last_command(void);
static void save_args(int argc, char **argv);
static int set_message_type(fko_ctx_t ctx, fko_cli_options_t *options);
static int set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options);
static int get_rand_port(fko_ctx_t ctx);
static void dump_transmit_options(fko_cli_options_t *options);
int resolve_ip_http(fko_cli_options_t *options);
int
main(int argc, char **argv)
{
fko_ctx_t ctx, ctx2;
int res;
char *spa_data, *version;
char access_buf[MAX_LINE_LEN];
fko_cli_options_t options;
/* Handle command line
*/
config_init(&options, argc, argv);
/* Handle options that don't require a libfko context
*/
if(options.show_last_command)
show_last_command();
else if (!options.no_save_args)
save_args(argc, argv);
/* Intialize the context
*/
res = fko_new(&ctx);
if(res != FKO_SUCCESS)
{
errmsg("fko_new", res);
return(EXIT_FAILURE);
}
/* Display version info and exit.
*/
if (options.version) {
fko_get_version(ctx, &version);
fprintf(stdout, "[+] fwknop client %s, FKO protocol version %s\n",
MY_VERSION, version);
return(EXIT_SUCCESS);
}
/* Set client timeout
*/
if(options.fw_timeout >= 0)
{
res = fko_set_spa_client_timeout(ctx, options.fw_timeout);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_spa_client_timeout", res);
return(EXIT_FAILURE);
}
}
/* Set the SPA packet message type based on command line options
*/
res = set_message_type(ctx, &options);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_spa_message_type", res);
return(EXIT_FAILURE);
}
if(options.server_command[0] != 0x0)
{
/* Set the access message to a command that the server will
* execute
*/
snprintf(access_buf, MAX_LINE_LEN, "%s%s%s",
options.allow_ip_str, ",", options.server_command);
}
else
{
/* Resolve the client's public facing IP address if requestesd.
* if this fails, consider it fatal.
*/
if (options.resolve_ip_http)
if(resolve_ip_http(&options) < 0)
return(EXIT_FAILURE);
/* Set a message string by combining the allow IP and the
* port/protocol. The fwknopd server allows no port/protocol
* to be specified as well, so in this case append the string
* "none/0" to the allow IP.
*/
if(options.access_str[0] != 0x0)
{
snprintf(access_buf, MAX_LINE_LEN, "%s%s%s",
options.allow_ip_str, ",", options.access_str);
}
else
{
snprintf(access_buf, MAX_LINE_LEN, "%s%s%s",
options.allow_ip_str, ",", "none/0");
}
}
res = fko_set_spa_message(ctx, access_buf);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_spa_message", res);
return(EXIT_FAILURE);
}
/* Set NAT access string
*/
if (options.nat_local || options.nat_access_str[0] != 0x0)
{
res = set_nat_access(ctx, &options);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_nat_access_str", res);
return(EXIT_FAILURE);
}
}
/* Set username
*/
if(options.spoof_user[0] != 0x0)
{
res = fko_set_username(ctx, options.spoof_user);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_username", res);
return(EXIT_FAILURE);
}
}
/* Set up for using GPG if specified.
*/
if(options.use_gpg)
{
/* If use-gpg-agent was not specified, then remove the GPG_AGENT_INFO
* ENV variable if it exists.
*/
#ifndef WIN32
if(!options.use_gpg_agent)
unsetenv("GPG_AGENT_INFO");
#endif
res = fko_set_spa_encryption_type(ctx, FKO_ENCRYPTION_GPG);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_spa_encryption_type", res);
return(EXIT_FAILURE);
}
/* If a GPG home dir was specified, set it here. Note: Setting
* this has to occur before calling any of the other GPG-related
* functions.
*/
if(options.gpg_home_dir != NULL && strlen(options.gpg_home_dir) > 0)
{
res = fko_set_gpg_home_dir(ctx, options.gpg_home_dir);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_gpg_home_dir", res);
return(EXIT_FAILURE);
}
}
res = fko_set_gpg_recipient(ctx, options.gpg_recipient_key);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_gpg_recipient", res);
if(IS_GPG_ERROR(res))
fprintf(stderr, "GPG ERR: %s\n", fko_gpg_errorstr(ctx));
return(EXIT_FAILURE);
}
if(options.gpg_signer_key != NULL && strlen(options.gpg_signer_key))
{
res = fko_set_gpg_signer(ctx, options.gpg_signer_key);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_gpg_signer", res);
if(IS_GPG_ERROR(res))
fprintf(stderr, "GPG ERR: %s\n", fko_gpg_errorstr(ctx));
return(EXIT_FAILURE);
}
}
}
/* Set Digest type.
*/
if(options.digest_type)
{
fko_set_spa_digest_type(ctx, options.digest_type);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_spa_digest_type", res);
return(EXIT_FAILURE);
}
}
/* Finalize the context data (encrypt and encode the SPA data)
*/
res = fko_spa_data_final(ctx, get_user_pw(&options, CRYPT_OP_ENCRYPT));
if(res != FKO_SUCCESS)
{
errmsg("fko_spa_data_final", res);
if(IS_GPG_ERROR(res))
fprintf(stderr, "GPG ERR: %s\n", fko_gpg_errorstr(ctx));
return(EXIT_FAILURE);
}
/* Display the context data.
*/
if (options.verbose || options.test)
display_ctx(ctx);
/* Save packet data payload if requested.
*/
if (options.save_packet_file[0] != 0x0)
write_spa_packet_data(ctx, &options);
if (options.rand_port)
options.spa_dst_port = get_rand_port(ctx);
if (options.verbose)
dump_transmit_options(&options);
/* If not in test mode, send the SPA data across the wire with a
* protocol/port specified on the command line (default is UDP/62201).
* Otherwise, run through a decode cycle (--DSS XXX: This test/decode
* portion should be moved elsewhere).
*/
if (!options.test)
{
res = send_spa_packet(ctx, &options);
if(res < 0)
{
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);
}
}
else
{
/************** Decoding now *****************/
/* Now we create a new context based on data from the first one.
*/
res = fko_get_spa_data(ctx, &spa_data);
if(res != FKO_SUCCESS)
{
errmsg("fko_get_spa_data", res);
return(EXIT_FAILURE);
}
/* If gpg-home-dir is specified, we have to defer decrypting if we
* use the fko_new_with_data() function because we need to set the
* gpg home dir after the context is created, but before we attempt
* to decrypt the data. Therefore we either pass NULL for the
* decryption key to fko_new_with_data() or use fko_new() to create
* an empty context, populate it with the encrypted data, set our
* options, then decode it.
*/
res = fko_new_with_data(&ctx2, spa_data, NULL);
if(res != FKO_SUCCESS)
{
errmsg("fko_new_with_data", res);
return(EXIT_FAILURE);
}
/* See if we are using gpg and if we need to set the GPG home dir.
*/
if(options.use_gpg)
{
if(options.gpg_home_dir != NULL && strlen(options.gpg_home_dir) > 0)
{
res = fko_set_gpg_home_dir(ctx2, options.gpg_home_dir);
if(res != FKO_SUCCESS)
{
errmsg("fko_set_gpg_home_dir", res);
return(EXIT_FAILURE);
}
}
}
res = fko_decrypt_spa_data(
ctx2, get_user_pw(&options, CRYPT_OP_DECRYPT)
);
if(res != FKO_SUCCESS)
{
errmsg("fko_decrypt_spa_data", res);
if(IS_GPG_ERROR(res)) {
/* we most likely could not decrypt the gpg-encrypted data
* because we don't have access to the private key associated
* with the public key we used for encryption. Since this is
* expected, return 0 instead of an error condition (so calling
* programs like the fwknop test suite don't interpret this as
* an unrecoverable error), but print the error string for
debugging purposes. */
fprintf(stderr, "GPG ERR: %s\n%s\n", fko_gpg_errorstr(ctx2),
"[*] No access to recipient private key?\n");
return(EXIT_SUCCESS);
}
return(EXIT_FAILURE);
}
printf("\nDump of the Decoded Data\n");
display_ctx(ctx2);
fko_destroy(ctx2);
}
fko_destroy(ctx);
return(EXIT_SUCCESS);
}
static void
print_proto(int proto)
{
switch (proto) {
case FKO_PROTO_UDP:
printf("udp");
break;
case FKO_PROTO_TCP_RAW:
printf("tcpraw");
break;
case FKO_PROTO_TCP:
printf("tcp");
break;
case FKO_PROTO_ICMP:
printf("icmp");
break;
case FKO_PROTO_HTTP:
printf("http");
break;
}
return;
}
static int
get_rand_port(fko_ctx_t ctx)
{
char *rand_val = NULL;
int port = 0;
int res = 0;
res = fko_get_rand_value(ctx, &rand_val);
if(res != FKO_SUCCESS)
{
errmsg("get_rand_port(), fko_get_rand_value", res);
exit(EXIT_FAILURE);
}
/* Convert to a random value between 1024 and 65535
*/
port = (MIN_HIGH_PORT + (abs(atoi(rand_val)) % (MAX_PORT - MIN_HIGH_PORT)));
/* Force libfko to calculate a new random value since we don't want to
* given anyone a hint (via the port value) about the contents of the
* encrypted SPA data.
*/
res = fko_set_rand_value(ctx, NULL);
if(res != FKO_SUCCESS)
{
errmsg("get_rand_port(), fko_get_rand_value", res);
exit(EXIT_FAILURE);
}
return port;
}
static void
dump_transmit_options(fko_cli_options_t *options)
{
printf("[+] Generating SPA packet:\n protocol: ");
print_proto(options->spa_proto),
printf("\n port: %d\n", options->spa_dst_port);
return;
}
/* See if the string is of the format "<ipv4 addr>:<port>",
* e.g. "123.1.2.3,12345" - this needs work.
*/
static int
ipv4_str_has_port(char *str)
{
int rv = 0, i;
int st_len = strlen(str);
for (i=0; i < st_len; i++) {
if (str[i] == ',' || str[i] == ':') {
str[i] = ','; /* force "<ip>,<port>" format */
rv = 1;
continue;
}
if (rv && ! isdigit(str[i])) {
rv = 0;
break;
}
}
return rv;
}
/* Set NAT access string
*/
static int
set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options)
{
char nat_access_buf[MAX_LINE_LEN] = "";
int nat_port = 0;
if (options->nat_rand_port)
nat_port = get_rand_port(ctx);
else if (options->nat_port)
nat_port = options->nat_port;
else
nat_port = DEFAULT_NAT_PORT;
if (options->nat_local && options->nat_access_str[0] == 0x0)
{
snprintf(nat_access_buf, MAX_LINE_LEN, "%s,%d",
options->spa_server_str, nat_port);
}
if (nat_access_buf[0] == 0x0 && options->nat_access_str[0] != 0x0)
{
if (ipv4_str_has_port(options->nat_access_str))
{
snprintf(nat_access_buf, MAX_LINE_LEN, "%s",
options->nat_access_str);
}
else
{
snprintf(nat_access_buf, MAX_LINE_LEN, "%s,%d",
options->nat_access_str, nat_port);
}
}
return fko_set_spa_nat_access(ctx, nat_access_buf);
}
static int
get_save_file(char *args_save_file)
{
char *homedir = NULL;
int rv = 0;
homedir = getenv("HOME");
if (homedir != NULL) {
snprintf(args_save_file, MAX_PATH_LEN, "%s%s%s",
homedir, "/", ".fwknop.run");
rv = 1;
}
return rv;
}
/* Show the last command that was executed
*/
static void
show_last_command(void)
{
char args_save_file[MAX_PATH_LEN];
char args_str[MAX_LINE_LEN] = "";
FILE *args_file_ptr = NULL;
#ifdef WIN32
/* Not sure what the right thing is here on Win32, just exit
* for now.
*/
printf("[*] --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) {
printf("[*] 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);
} else {
printf("[-] Could not read line from file: %s\n", args_save_file);
}
fclose(args_file_ptr);
}
exit(EXIT_SUCCESS);
}
/* Save our command line arguments
*/
static void
save_args(int argc, char **argv)
{
char args_save_file[MAX_PATH_LEN];
char args_str[MAX_LINE_LEN] = "";
FILE *args_file_ptr = NULL;
int i = 0, args_str_len;
#ifdef WIN32
/* Not sure what the right thing is here on Win32, just return
* for now.
*/
return;
#endif
if (get_save_file(args_save_file)) {
if ((args_file_ptr = fopen(args_save_file, "w")) == NULL) {
printf("[*] 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) {
printf("[*] argument string too long, exiting.\n");
exit(EXIT_FAILURE);
}
strlcat(args_str, argv[i], MAX_PATH_LEN);
strlcat(args_str, " ", MAX_PATH_LEN);
}
fprintf(args_file_ptr, "%s\n", args_str);
fclose(args_file_ptr);
}
return;
}
/* Set the SPA packet message type
*/
static int
set_message_type(fko_ctx_t ctx, fko_cli_options_t *options)
{
short message_type;
if(options->server_command[0] != 0x0)
{
message_type = FKO_COMMAND_MSG;
}
else if(options->nat_access_str[0] != 0x0)
{
if (options->nat_local)
{
if (options->fw_timeout >= 0)
{
message_type = FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG;
}
else
{
message_type = FKO_LOCAL_NAT_ACCESS_MSG;
}
}
else
{
if (options->fw_timeout >= 0)
{
message_type = FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG;
}
else
{
message_type = FKO_NAT_ACCESS_MSG;
}
}
}
else
{
if (options->fw_timeout >= 0)
{
message_type = FKO_CLIENT_TIMEOUT_ACCESS_MSG;
}
else
{
message_type = FKO_ACCESS_MSG;
}
}
return fko_set_spa_message_type(ctx, message_type);
}
/* Prompt for and receive a user password.
*/
char*
get_user_pw(fko_cli_options_t *options, int crypt_op)
{
if (options->get_key_file[0] != 0x0) {
/* grab the key/password from the --get-key file
*/
return(getpasswd_file(options->get_key_file,
options->spa_server_str));
}
else if (options->use_gpg) {
return(options->use_gpg_agent ? ""
: getpasswd("Enter passphrase for secret key: "));
}
else
{
if(crypt_op == CRYPT_OP_ENCRYPT)
return(getpasswd("Enter encryption password: "));
else if(crypt_op == CRYPT_OP_DECRYPT)
return(getpasswd("Enter decryption password: "));
else
return(getpasswd("Enter password: "));
}
}
/* Display an FKO error message.
*/
void
errmsg(char *msg, int err) {
fprintf(stderr, "[*] %s: %s: Error %i - %s\n",
MY_NAME, msg, err, fko_errstr(err));
}
/* Show the fields of the FKO context.
*/
static void
display_ctx(fko_ctx_t ctx)
{
char *rand_val = NULL;
char *username = NULL;
char *version = NULL;
char *spa_message = NULL;
char *nat_access = NULL;
char *server_auth = NULL;
char *enc_data = NULL;
char *spa_digest = NULL;
char *spa_data = NULL;
time_t timestamp = 0;
short msg_type = -1;
short digest_type = -1;
int client_timeout = -1;
/* Should be checking return values, but this is temp code. --DSS
*/
fko_get_rand_value(ctx, &rand_val);
fko_get_username(ctx, &username);
fko_get_timestamp(ctx, &timestamp);
fko_get_version(ctx, &version);
fko_get_spa_message_type(ctx, &msg_type);
fko_get_spa_message(ctx, &spa_message);
fko_get_spa_nat_access(ctx, &nat_access);
fko_get_spa_server_auth(ctx, &server_auth);
fko_get_spa_client_timeout(ctx, &client_timeout);
fko_get_spa_digest_type(ctx, &digest_type);
fko_get_encoded_data(ctx, &enc_data);
fko_get_spa_digest(ctx, &spa_digest);
fko_get_spa_data(ctx, &spa_data);
printf("\nFKO Field Values:\n=================\n\n");
printf(" Random Value: %s\n", rand_val == NULL ? "<NULL>" : rand_val);
printf(" Username: %s\n", username == NULL ? "<NULL>" : username);
printf(" Timestamp: %u\n", (unsigned int) timestamp);
printf(" FKO Version: %s\n", version == NULL ? "<NULL>" : version);
printf(" Message Type: %i\n", msg_type);
printf(" Message String: %s\n", spa_message == NULL ? "<NULL>" : spa_message);
printf(" Nat Access: %s\n", nat_access == NULL ? "<NULL>" : nat_access);
printf(" Server Auth: %s\n", server_auth == NULL ? "<NULL>" : server_auth);
printf(" Client Timeout: %u\n", client_timeout);
printf(" Digest Type: %u\n", digest_type);
printf("\n Encoded Data: %s\n", enc_data == NULL ? "<NULL>" : enc_data);
printf("\nSPA Data Digest: %s\n", spa_digest == NULL ? "<NULL>" : spa_digest);
printf("\nFinal Packed/Encrypted/Encoded Data:\n\n%s\n\n", spa_data);
}
/***EOF***/

37
client/fwknop.h Normal file
View File

@@ -0,0 +1,37 @@
/* $Id$
*****************************************************************************
*
* File: fwknop.h
*
* Author: Damien S. Stuart (dstuart@dstuart.org)
* Michael Rash (mbr@cipherdyne.org)
*
* Purpose: Header file for fwknop client test program.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#ifndef FWKNOP_H
#define FWKNOP_H
#include "fwknop_common.h"
/* Used by the get_user_pw function below.
*/
#define CRYPT_OP_ENCRYPT 1
#define CRYPT_OP_DECRYPT 2
#endif /* FWKNOP_H */

122
client/fwknop_common.h Normal file
View File

@@ -0,0 +1,122 @@
/*
******************************************************************************
*
* File: fwknop_common.h
*
* Author: Damien Stuart
*
* Purpose: Header file for fwknop config_init.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
******************************************************************************
*/
#ifndef FWKNOP_COMMON_H
#define FWKNOP_COMMON_H
#include "common.h"
/* My Name and Version
*/
#define MY_NAME "fwknop"
#define MY_DESC "Single Packet Authorization client"
/* Get our program version from VERSION (defined in config.h).
*/
#define MY_VERSION VERSION
/* Default config path, can override with -c
*/
#define DEF_CONFIG_FILE MY_NAME".conf"
/* For time offset handling
*/
#define MAX_TIME_STR_LEN 9
#define TIME_OFFSET_SECONDS 1
#define TIME_OFFSET_MINUTES 60
#define TIME_OFFSET_HOURS 3600
#define TIME_OFFSET_DAYS 86400
/* For resolving the allow IP via HTTP and sending SPA packets over
* HTTP
*/
#define HTTP_RESOLVE_HOST "www.cipherdyne.org"
#define HTTP_RESOLVE_URL "/cgi/myip.cgi"
#define HTTP_MAX_REQUEST_LEN 2000
#define HTTP_MAX_RESPONSE_LEN 2000
#define HTTP_MAX_USER_AGENT_LEN 50
/* fwknop client configuration parameters and values
*/
typedef struct fko_cli_options
{
char config_file[MAX_PATH_LEN];
char access_str[MAX_PATH_LEN];
char server_command[MAX_LINE_LEN];
char get_key_file[MAX_LINE_LEN];
char save_packet_file[MAX_LINE_LEN];
int save_packet_file_append;
int show_last_command;
int no_save_args;
char spa_server_str[MAX_SERVER_STR_LEN]; /* may be a hostname */
char allow_ip_str[MAX_IP_STR_LEN];
char spoof_ip_src_str[MAX_IP_STR_LEN];
char spoof_user[MAX_USERNAME_LEN];
int rand_port;
char gpg_recipient_key[MAX_GPG_KEY_ID];
char gpg_signer_key[MAX_GPG_KEY_ID];
char gpg_home_dir[MAX_PATH_LEN];
/* NAT access
*/
char nat_access_str[MAX_PATH_LEN];
int nat_local;
int nat_port;
int nat_rand_port;
/* External IP resolution via HTTP
*/
int resolve_ip_http;
char http_user_agent[HTTP_MAX_USER_AGENT_LEN];
/* SPA packet transmission port and protocol
*/
int spa_proto;
unsigned int spa_dst_port;
unsigned int spa_src_port; /* only used with --source-port */
unsigned int digest_type;
/* Various command-line flags */
unsigned char quiet; /* --quiet mode */
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;
int time_offset_plus;
int time_offset_minus;
int fw_timeout;
//char config_file[MAX_PATH_LEN];
} fko_cli_options_t;
extern fko_cli_options_t options;
#endif /* FWKNOP_COMMON_H */
/***EOF***/

213
client/getpasswd.c Normal file
View File

@@ -0,0 +1,213 @@
/* $Id$
*****************************************************************************
*
* File: getpasswd.c
*
* Author: Damien S. Stuart
*
* Purpose: Routines for obtaining a password from a user.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#include <stdio.h>
#include <signal.h>
#ifdef WIN32
#include <conio.h>
#else
#include <termios.h>
#endif
#include "fwknop_common.h"
#include "getpasswd.h"
#define MAX_PASS_LEN 128
/* Function for accepting password input from users
*/
char*
getpasswd(const char *prompt)
{
static char pwbuf[MAX_PASS_LEN + 1] = {0};
char *ptr;
int c;
#ifndef WIN32
FILE *fp;
sigset_t sig, old_sig;
struct termios ts, old_ts;
if((fp = fopen(ctermid(NULL), "r+")) == NULL)
return(NULL);
setbuf(fp, NULL);
/* Setup blocks for SIGINT and SIGTSTP and save the original signal
* mask.
*/
sigemptyset(&sig);
sigaddset(&sig, SIGINT);
sigaddset(&sig, SIGTSTP);
sigprocmask(SIG_BLOCK, &sig, &old_sig);
/* Save current tty state for later restoration after we disable echo
* of characters to the tty.
*/
tcgetattr(fileno(fp), &ts);
old_ts = ts;
ts.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
tcsetattr(fileno(fp), TCSAFLUSH, &ts);
fputs(prompt, fp);
#endif
/* Read in the password.
*/
ptr = pwbuf;
#ifdef WIN32
_cputs(prompt);
while((c = _getch()) != '\r')
{
/* Handle a backspace without backing up too far.
*/
if(c == '\b')
{
if(ptr != pwbuf)
*ptr--;
continue;
}
/* Handle a Ctrl-U to clear the password entry and start over
* (like it works under Unix).
*/
if(c == 0x15)
{
ptr = pwbuf;
continue;
}
#else
while((c = getc(fp)) != EOF && c != '\n')
{
#endif
if(ptr < &pwbuf[MAX_PASS_LEN])
*ptr++ = c;
}
/* Null terminate the password.
*/
*ptr = 0;
#ifndef WIN32
/* we can go ahead and echo out a newline.
*/
putc('\n', fp);
/* Restore our tty state and signal handlers.
*/
tcsetattr(fileno(fp), TCSAFLUSH, &old_ts);
sigprocmask(SIG_BLOCK, &old_sig, NULL);
fclose(fp);
#else
/* In Windows, it would be a CR-LF
*/
_putch('\r');
_putch('\n');
#endif
return(pwbuf);
}
/* Function for accepting password input from from a file
*/
char*
getpasswd_file(const char *pw_file, const char *server_str)
{
FILE *pwfile_ptr;
unsigned int numLines = 0, i = 0, found_dst;
static char pwbuf[MAX_PASS_LEN + 1] = {0};
char conf_line_buf[MAX_LINE_LEN] = {0};
char tmp_char_buf[MAX_LINE_LEN] = {0};
char *lptr;
if ((pwfile_ptr = fopen(pw_file, "r")) == NULL)
{
fprintf(stderr, "[*] Could not open config file: %s\n", pw_file);
exit(1);
}
while ((fgets(conf_line_buf, MAX_LINE_LEN, pwfile_ptr)) != NULL)
{
numLines++;
conf_line_buf[MAX_LINE_LEN-1] = '\0';
lptr = conf_line_buf;
memset(tmp_char_buf, 0x0, MAX_LINE_LEN);
while (*lptr == ' ' || *lptr == '\t' || *lptr == '=')
lptr++;
/* Get past comments and empty lines.
*/
if (*lptr == '#' || *lptr == '\n' || *lptr == '\r' || *lptr == '\0' || *lptr == ';')
continue;
/* Look for a line like "<SPA destination IP>: <password>" - this allows
* multiple keys to be placed within the same file, and the client will
* reference the matching one for the SPA server we are contacting
*/
found_dst = 1;
for (i=0; i < strlen(server_str); i++)
if (*lptr++ != server_str[i])
found_dst = 0;
if (! found_dst)
continue;
if (*lptr == ':')
lptr++;
else
continue;
/* Skip whitespace until we get to the password
*/
while (*lptr == ' ' || *lptr == '\t' || *lptr == '=')
lptr++;
i = 0;
while (*lptr != '\0' && *lptr != '\n') {
pwbuf[i] = *lptr;
lptr++;
i++;
}
pwbuf[i] = '\0';
}
fclose(pwfile_ptr);
if (pwbuf[0] == '\0') {
fprintf(stderr, "[*] Could not get password for IP: %s from: %s\n",
server_str, pw_file);
exit(1);
}
return pwbuf;
}
/***EOF***/

34
client/getpasswd.h Normal file
View File

@@ -0,0 +1,34 @@
/*
*****************************************************************************
*
* File: getpasswd.h
*
* Author: Damien Stuart (dstuart@dstuart.org)
*
* Purpose: Header file for getpasswd.c.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#ifndef GETPASSWD_H
#define GETPASSWD_H
/* Prototypes
*/
char* getpasswd(const char *prompt);
char* getpasswd_file(const char *pw_file, const char *server_str);
#endif /* GETPASSWD_H */

140
client/http_resolve_host.c Normal file
View File

@@ -0,0 +1,140 @@
/*
*****************************************************************************
*
* File: http_resolve_host.c
*
* Author: Damien S. Stuart
*
* Purpose: Routine for using an http request to obtain a client's IP
* address as seen from the outside world.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#include "fwknop_common.h"
#include <netdb.h>
int
resolve_ip_http(fko_cli_options_t *options)
{
int sock, res, error, http_buf_len, i;
struct addrinfo *result, *rp, hints;
char http_buf[HTTP_MAX_REQUEST_LEN];
char http_response[HTTP_MAX_RESPONSE_LEN];
/* Build our HTTP request to resolve the external IP (this is similar to
* to contacting whatismyip.org, but using a different URL).
*/
snprintf(http_buf, HTTP_MAX_REQUEST_LEN,
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nAccept: */*\r\n"
"Host: %s\r\nConnection: Keep-Alive\r\n\r\n",
HTTP_RESOLVE_URL, options->http_user_agent, HTTP_RESOLVE_HOST
);
http_buf_len = strlen(http_buf);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
error = getaddrinfo(HTTP_RESOLVE_HOST, "80", &hints, &result);
if (error != 0)
{
fprintf(stderr, "[*] error in getaddrinfo: %s\n", gai_strerror(error));
return(-1);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sock < 0)
continue;
if (error = connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* made it */
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
}
if (rp == NULL) {
perror("[*] resolve_ip_http: Could not create socket: ");
return(-1);
}
freeaddrinfo(result);
res = send(sock, http_buf, http_buf_len, 0);
if(res < 0)
{
perror("[*] resolve_ip_http: write error: ");
}
else if(res != http_buf_len)
{
fprintf(stderr,
"[#] Warning: bytes sent (%i) not spa data length (%i).\n",
res, http_buf_len
);
}
res = recv(sock, http_response, HTTP_MAX_RESPONSE_LEN, 0);
http_response[HTTP_MAX_RESPONSE_LEN-1] = '\0';
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
/* Now parse the response for the IP address (which should be at
* the end of the string
*/
for (i=res-3; i >= 0; i--)
{
if(http_response[i] == '\n')
break;
if(http_response[i] != '.' && ! isdigit(http_response[i]))
{
fprintf(stderr, "[*] Invalid IP in HTTP response.\n");
return(-1);
}
}
if (i < MIN_IP_STR_LEN)
{
fprintf(stderr, "[*] Invalid IP in HTTP response.\n");
return(-1);
}
http_response[res-1] = '\0';
strlcpy(options->allow_ip_str,
(http_response + i+1), (res - (i+2)));
if(options->verbose)
printf("[+] Resolved external IP (via http://%s%s) as: %s\n",
HTTP_RESOLVE_HOST, HTTP_RESOLVE_URL, options->allow_ip_str);
return(0);
}
/***EOF***/

536
client/spa_comm.c Normal file
View File

@@ -0,0 +1,536 @@
/* $Id$
*****************************************************************************
*
* File: spa_comm.c
*
* Author: Damien S. Stuart (dstuart@dstuart.org)
* Michael Rash (mbr@cipherdyne.org)
*
* Purpose: Network-related functions for the fwknop client
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#include "spa_comm.h"
/* Function to generate a header checksum.
*/
unsigned short
chksum(unsigned short *buf, int nbytes)
{
unsigned int sum;
unsigned short oddbyte;
sum = 0;
while (nbytes > 1)
{
sum += *buf++;
nbytes -= 2;
}
if (nbytes == 1)
{
oddbyte = 0;
*((unsigned short *) &oddbyte) = *(unsigned short *) buf;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return (unsigned short) ~sum;
}
static int is_ip(char *str)
{
int rv = 1;
unsigned int i;
for (i=0; i < strlen(str); i++) {
if (str[i] != '.' && ! isdigit(str[i])) {
rv = 0;
break;
}
}
return rv;
}
/* Send the SPA data via UDP packet.
*/
int
send_spa_packet_tcp_or_udp(char *spa_data, int sd_len, fko_cli_options_t *options)
{
int sock, res, error;
struct addrinfo *result, *rp, hints;
char port_str[MAX_PORT_STR_LEN];
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
if (options->spa_proto == FKO_PROTO_UDP)
{
/* Send the SPA data packet via an single UDP packet - this is the
* most common usage.
*/
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
}
else
{
/* Send the SPA data packet via an established TCP connection.
*/
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
}
sprintf(port_str, "%d", options->spa_dst_port);
error = getaddrinfo(options->spa_server_str, port_str, &hints, &result);
if (error != 0)
{
fprintf(stderr, "[*] error in getaddrinfo: %s\n", gai_strerror(error));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sock < 0)
continue;
if (error = connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* made it */
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
}
if (rp == NULL) {
perror("[*] send_spa_packet_tcp_or_udp: Could not create socket: ");
exit(EXIT_FAILURE);
}
freeaddrinfo(result);
res = send(sock, spa_data, sd_len, 0);
if(res < 0)
{
perror("[*] send_spa_packet_tcp_or_udp: write error: ");
}
else if(res != sd_len)
{
fprintf(stderr,
"[#] Warning: bytes sent (%i) not spa data length (%i).\n",
res, sd_len
);
}
#ifdef WIN32
closesocket(sock);
#else
close(sock);
#endif
return(res);
}
/* Send the SPA data via raw TCP packet.
*/
int
send_spa_packet_tcp_raw(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_tcp_raw: raw packets are not yet supported.\n");
return(-1);
#else
int sock, res;
char pkt_data[2048] = {0}; /* Should be enough for our purposes */
struct iphdr *iph = (struct iphdr *) pkt_data;
struct tcphdr *tcph = (struct tcphdr *) (pkt_data + sizeof (struct iphdr));
int hdrlen = sizeof(struct iphdr) + sizeof(struct tcphdr);
/* Values for setsockopt.
*/
int one = 1;
const int *so_val = &one;
sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock < 0)
{
perror("[*] send_spa_packet_tcp_raw: create socket: ");
return(sock);
}
/* Put the spa data in place.
*/
memcpy((pkt_data + hdrlen), spa_data, sd_len);
/* Construct our own header by filling in the ip/tcp header values,
* starting with the IP header values.
*/
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
/* Total size is header plus payload */
iph->tot_len = hdrlen + sd_len;
/* The value here does not matter */
iph->id = random() & 0xffff;
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_TCP;
iph->check = 0;
iph->saddr = saddr->sin_addr.s_addr;
iph->daddr = daddr->sin_addr.s_addr;
/* Now the TCP header values.
*/
tcph->source = saddr->sin_port;
tcph->dest = daddr->sin_port;
tcph->seq = htonl(1);
tcph->ack_seq = 0;
tcph->doff = 5;
tcph->res1 = 0;
/* TCP flags */
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->res2 = 0;
tcph->window = htons(32767);
tcph->check = 0;
tcph->urg_ptr = 0;
/* No we can compute our checksum.
*/
iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
/* Make sure the kernel knows the header is included in the data so it
* 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: ");
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: ");
}
else if(res != sd_len)
{
fprintf(stderr,
"[#] Warning: bytes sent (%i) not spa data length (%i).\n",
res, sd_len
);
}
close(sock);
return(res);
#endif /* !WIN32 */
}
/* Send the SPA data via ICMP packet.
*/
int
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");
return(-1);
#else
int res;
char pkt_data[2048] = {0};
struct iphdr *iph = (struct iphdr *) pkt_data;
struct icmphdr *icmph = (struct icmphdr *) (pkt_data + sizeof (struct iphdr));
int hdrlen = sizeof(struct iphdr) + sizeof(struct icmphdr);
/* Values for setsockopt.
*/
int one = 1;
const int *so_val = &one;
int sock = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock < 0)
{
perror("[*] send_spa_packet_icmp: create socket: ");
return(sock);
}
/* Put the spa data in place.
*/
memcpy((pkt_data + hdrlen), spa_data, sd_len);
/* Construct our own header by filling in the ip/icmp header values,
* starting with the IP header values.
*/
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
/* Total size is header plus payload */
iph->tot_len = hdrlen + sd_len;
/* The value here does not matter */
iph->id = random() & 0xffff;
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = IPPROTO_ICMP;
iph->check = 0;
iph->saddr = saddr->sin_addr.s_addr;
iph->daddr = daddr->sin_addr.s_addr;
/* Now the ICMP header values.
*/
icmph->type = ICMP_ECHOREPLY; /* Make it an echo reply */
icmph->code = 0;
icmph->checksum = 0;
/* No we can compute our checksum.
*/
iph->check = chksum((unsigned short *)pkt_data, iph->tot_len);
icmph->checksum = chksum((unsigned short *)icmph, sizeof(struct icmphdr) + sd_len);
/* Make sure the kernel knows the header is included in the data so it
* 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: ");
res = sendto (sock, pkt_data, iph->tot_len, 0,
(struct sockaddr *)daddr, sizeof(*daddr));
if(res < 0)
{
perror("[*] send_spa_packet_icmp: sendto error: ");
}
else if(res != sd_len)
{
fprintf(stderr, "[#] Warning: bytes sent (%i) not spa data length (%i).\n",
res, sd_len);
}
close(sock);
return(res);
#endif /* !WIN32 */
}
/* Send the SPA data packet via an HTTP request
*/
int
send_spa_packet_http(char *spa_data, int sd_len, fko_cli_options_t *options)
{
char http_buf[HTTP_MAX_REQUEST_LEN];
int i;
/* change "+" chars to "-", and "/" to "_" for HTTP requests (the server
* side will translate these back before decrypting) */
for (i=0; i < sd_len; i++) {
if (spa_data[i] == '+') {
spa_data[i] = '-';
}
else if (spa_data[i] == '/') {
spa_data[i] = '_';
}
}
snprintf(http_buf, HTTP_MAX_REQUEST_LEN,
"%s%s%s%s%s%s%s",
"GET ",
spa_data,
" HTTP/1.0\r\nUser-Agent: ",
options->http_user_agent,
"\r\nAccept: */*\r\nHost: ",
options->spa_server_str, /* hostname or IP */
"\r\nConnection: Keep-Alive\r\n\r\n"
);
return send_spa_packet_tcp_or_udp(http_buf, strlen(http_buf), options);
}
/* Function used to send the SPA data.
*/
int
send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options)
{
int res, sd_len;
char *spa_data;
struct sockaddr_in saddr, daddr;
#ifdef WIN32
WSADATA wsa_data;
#endif
/* Get our spa data here.
*/
res = fko_get_spa_data(ctx, &spa_data);
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"send_spa_packet: Error #%i from fko_get_spa_data: %s\n",
res, fko_errstr(res)
);
return(-1);
}
sd_len = strlen(spa_data);
#ifdef WIN32
/* Winsock needs to be initialized...
*/
res = WSAStartup( MAKEWORD(1,1), &wsa_data );
if( res != 0 )
{
fprintf(stderr, "[*] Winsock initialization error %d\n", res );
return(-1);
}
#endif
errno = 0;
if (options->spa_proto == FKO_PROTO_TCP || options->spa_proto == FKO_PROTO_UDP)
{
res = send_spa_packet_tcp_or_udp(spa_data, sd_len, options);
}
else if (options->spa_proto == FKO_PROTO_HTTP)
{
res = send_spa_packet_http(spa_data, sd_len, options);
}
else if (options->spa_proto == FKO_PROTO_TCP_RAW
|| options->spa_proto == FKO_PROTO_ICMP)
{
memset(&saddr, 0, sizeof(saddr));
memset(&daddr, 0, sizeof(daddr));
saddr.sin_family = AF_INET;
daddr.sin_family = AF_INET;
/* Set source address and port
*/
if (options->spa_src_port)
saddr.sin_port = htons(options->spa_src_port);
else
saddr.sin_port = INADDR_ANY; /* default */
if (options->spoof_ip_src_str[0] != 0x00) {
saddr.sin_addr.s_addr = inet_addr(options->spoof_ip_src_str);
} else
saddr.sin_addr.s_addr = INADDR_ANY; /* default */
if (saddr.sin_addr.s_addr == -1)
{
fprintf(stderr, "[*] Could not set source IP.\n");
exit(EXIT_FAILURE);
}
/* Set destination address and port
*/
daddr.sin_port = htons(options->spa_dst_port);
daddr.sin_addr.s_addr = inet_addr(options->spa_server_str);
if (daddr.sin_addr.s_addr == -1)
{
fprintf(stderr, "[*] Could not set destination IP.\n");
exit(EXIT_FAILURE);
}
if (options->spa_proto == FKO_PROTO_TCP_RAW)
{
res = send_spa_packet_tcp_raw(spa_data, sd_len, &saddr, &daddr, options);
}
else
{
res = send_spa_packet_icmp(spa_data, sd_len, &saddr, &daddr, options);
}
}
else
{
/* --DSS XXX: What to we really want to do here? */
fprintf(stderr, "[*] %i is not a valid or supported protocol.\n",
options->spa_proto);
res = -1;
}
return res;
}
/* Function to write SPA packet data to the filesystem
*/
int write_spa_packet_data(fko_ctx_t ctx, fko_cli_options_t *options)
{
FILE *fp;
char *spa_data;
int res;
res = fko_get_spa_data(ctx, &spa_data);
if(res != FKO_SUCCESS)
{
fprintf(stderr,
"write_spa_packet_data: Error #%i from fko_get_spa_data: %s\n",
res, fko_errstr(res)
);
return(-1);
}
if (options->save_packet_file_append)
{
fp = fopen(options->save_packet_file, "a");
}
else
{
unlink(options->save_packet_file);
fp = fopen(options->save_packet_file, "w");
}
if(fp == NULL)
{
perror("write_spa_packet_data: ");
return(-1);
}
fprintf(fp, "%s\n",
(spa_data == NULL) ? "<NULL>" : spa_data);
fclose(fp);
return(0);
}
/***EOF***/

147
client/spa_comm.h Normal file
View File

@@ -0,0 +1,147 @@
/*
*****************************************************************************
*
* File: spa_comm.h
*
* Author: Damien Stuart (dstuart@dstuart.org)
*
* Purpose: Header file for fwknop client test program.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#ifndef SPA_COMM_H
#define SPA_COMM_H
#include "fwknop_common.h"
#include <errno.h>
#ifdef WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <netdb.h>
#endif
/* We will roll our own packet header structs. */
/* The IP header
*/
struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
#error "Please fix <bits/endian.h>"
#endif
unsigned char tos;
unsigned short tot_len;
unsigned short id;
unsigned short frag_off;
unsigned char ttl;
unsigned char protocol;
unsigned short check;
unsigned int saddr;
unsigned int daddr;
};
/* The TCP header
*/
struct tcphdr
{
unsigned short source;
unsigned short dest;
unsigned int seq;
unsigned int ack_seq;
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned short res1:4;
unsigned short doff:4;
unsigned short fin:1;
unsigned short syn:1;
unsigned short rst:1;
unsigned short psh:1;
unsigned short ack:1;
unsigned short urg:1;
unsigned short res2:2;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned short doff:4;
unsigned short res1:4;
unsigned short res2:2;
unsigned short urg:1;
unsigned short ack:1;
unsigned short psh:1;
unsigned short rst:1;
unsigned short syn:1;
unsigned short fin:1;
#else
#error "Adjust your <bits/endian.h> defines"
#endif
unsigned short window;
unsigned short check;
unsigned short urg_ptr;
};
/* The ICMP header
*/
struct icmphdr
{
unsigned char type; /* message type */
unsigned char code; /* type sub-code */
unsigned short checksum;
union
{
struct
{
unsigned short id;
unsigned short sequence;
} echo; /* echo datagram */
unsigned int gateway; /* gateway address */
struct
{
unsigned short __unused;
unsigned short mtu;
} frag; /* path mtu discovery */
} un;
};
#define ICMP_ECHOREPLY 0 /* Echo Reply */
#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */
#define ICMP_SOURCE_QUENCH 4 /* Source Quench */
#define ICMP_REDIRECT 5 /* Redirect (change route) */
#define ICMP_ECHO 8 /* Echo Request */
#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */
#define ICMP_PARAMETERPROB 12 /* Parameter Problem */
#define ICMP_TIMESTAMP 13 /* Timestamp Request */
#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */
#define ICMP_INFO_REQUEST 15 /* Information Request */
#define ICMP_INFO_REPLY 16 /* Information Reply */
#define ICMP_ADDRESS 17 /* Address Mask Request */
#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */
/* Function Prototypes
*/
int send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options);
int write_spa_packet_data(fko_ctx_t ctx, fko_cli_options_t *options);
#endif /* SPA_COMM_H */

68
client/utils.c Normal file
View File

@@ -0,0 +1,68 @@
/* $Id$
*****************************************************************************
*
* File: utils.c
*
* Author: Damien S. Stuart
*
* Purpose: General/Generic functions for the fwknop client.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#include <stdio.h>
#include <string.h>
#include "utils.h"
/* Generic hex dump function.
*/
void
hex_dump(unsigned char *data, int size)
{
int ln, i, j = 0;
char ascii_str[17] = {0};
for(i=0; i<size; i++)
{
if((i % 16) == 0)
{
printf(" %s\n 0x%.4x: ", ascii_str, i);
memset(ascii_str, 0x0, 17);
j = 0;
}
printf("%.2x ", data[i]);
ascii_str[j++] = (data[i] < 0x20 || data[i] > 0x7e) ? '.' : data[i];
if(j == 8)
printf(" ");
}
/* Remainder...
*/
ln = strlen(ascii_str);
if(ln > 0)
{
for(i=0; i < 16-ln; i++)
printf(" ");
printf(" %s\n\n", ascii_str);
}
}
/***EOF***/

42
client/utils.h Normal file
View File

@@ -0,0 +1,42 @@
/*
*****************************************************************************
*
* File: utils.h
*
* Author: Damien Stuart (dstuart@dstuart.org)
*
* Purpose: Header file for utils.c client test program.
*
* Copyright (C) 2009 Damien Stuart (dstuart@dstuart.org)
*
* License (GNU Public License):
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
*****************************************************************************
*/
#ifndef UTILS_H
#define UTILS_H
/* Prototypes
*/
void hex_dump(unsigned char *data, int size);
#ifdef WIN32
/* Function prototypes we need for Windows
*/
size_t strlcat(char *dst, const char *src, size_t siz);
size_t strlcpy(char *dst, const char *src, size_t siz);
#endif
#endif /* UTILS_H */