[server] Added '--pcap-file <file>' option

Added a new '--pcap-file <file>' option to allow pcap files to
be processed directly by fwknopd instead of sniffing an interface.  This
feature is mostly intended for debugging purposes.
This commit is contained in:
Michael Rash 2012-11-08 21:33:23 -05:00
parent 7afe5b28b7
commit 66ad134708
12 changed files with 157 additions and 31 deletions

View File

@ -58,6 +58,9 @@ fwknop-2.0.4 (11//2012):
- [test suite] For GnuPG tests that require a passphrase associated with
a gpg key, added a pinentry check to see if the local gpg engine
requires it. If so, the gpg test that require a key are excluded since.
- [server] Added a new '--pcap-file <file>' option to allow pcap files to
be processed directly by fwknopd instead of sniffing an interface. This
feature is mostly intended for debugging purposes.
fwknop-2.0.3 (09/03/2012):
- [server] Fernando Arnaboldi from IOActive found several DoS/code

View File

@ -160,6 +160,7 @@ EXTRA_DIST = \
test/conf/tcp_pcap_filter_fwknopd.conf \
test/conf/icmp_pcap_filter_fwknopd.conf \
test/conf/tcp_server_fwknopd.conf \
test/conf/spa_replay.pcap \
test/fuzzing/patches/enable_perl_fko_bogus_packets.patch \
test/fuzzing/patches/encoding_append_b64_modified_byte \
test/fuzzing/patches/encoding_append_b64_modified_byte_eq.patch \

View File

@ -102,6 +102,12 @@ COMMAND-LINE OPTIONS
line. This overrides the value of the PCAP_FILTER variable taken
from the 'fwknopd.conf' file.
*--pcap-file*='<pcap-file>'::
This option instructs *fwknopd* to read packet data from a pcap file
instead of sniffing an interface directly. This mode is usually used for
debugging purposes, and will disable SPA packet age checking unless it is
manually enabled in the 'fwknop.conf' file.
*-R, --Restart*::
Restart the currently running *fwknopd* processes. This option
will preserve the command line options that were supplied to the

View File

@ -42,6 +42,7 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = {
"OVERRIDE_CONFIG",
//"FIREWALL_TYPE",
"PCAP_INTF",
"PCAP_FILE",
"ENABLE_PCAP_PROMISC",
"PCAP_FILTER",
"PCAP_DISPATCH_COUNT",
@ -115,6 +116,7 @@ enum {
FW_LIST_ALL,
FW_FLUSH,
GPG_HOME_DIR,
PCAP_FILE,
ROTATE_DIGEST_CACHE,
NOOP /* Just to be a marker for the end */
};
@ -143,6 +145,7 @@ static struct option cmd_opts[] =
{"locale", 1, NULL, 'l' },
{"rotate-digest-cache", 0, NULL, ROTATE_DIGEST_CACHE },
{"override-config", 1, NULL, 'O' },
{"pcap-file", 1, NULL, PCAP_FILE },
{"pcap-filter", 1, NULL, 'P'},
{"pid-file", 1, NULL, 'p'},
{"restart", 0, NULL, 'R'},

View File

@ -337,7 +337,8 @@ validate_options(fko_srv_options_t *opts)
/* Set remaining require CONF_ vars if they are not already set. */
/* PCAP capture interface.
/* PCAP capture interface - note that if '-r <pcap file>' is specified
* on the command line, then this will override the pcap interface setting.
*/
if(opts->config[CONF_PCAP_INTF] == NULL)
set_config_entry(opts, CONF_PCAP_INTF, DEF_INTERFACE);
@ -365,11 +366,21 @@ validate_options(fko_srv_options_t *opts)
if(opts->config[CONF_PCAP_FILTER] == NULL)
set_config_entry(opts, CONF_PCAP_FILTER, DEF_PCAP_FILTER);
/* Enable SPA packet aging.
/* Enable SPA packet aging unless we're getting packet data
* directly from a pcap file
*/
if(opts->config[CONF_ENABLE_SPA_PACKET_AGING] == NULL)
set_config_entry(opts, CONF_ENABLE_SPA_PACKET_AGING,
DEF_ENABLE_SPA_PACKET_AGING);
{
if(opts->config[CONF_PCAP_FILE] == NULL)
{
set_config_entry(opts, CONF_ENABLE_SPA_PACKET_AGING,
DEF_ENABLE_SPA_PACKET_AGING);
}
else
{
set_config_entry(opts, CONF_ENABLE_SPA_PACKET_AGING, "N");
}
}
/* SPA packet age.
*/
@ -798,6 +809,9 @@ config_init(fko_srv_options_t *opts, int argc, char **argv)
case 'P':
set_config_entry(opts, CONF_PCAP_FILTER, optarg);
break;
case PCAP_FILE:
set_config_entry(opts, CONF_PCAP_FILE, optarg);
break;
case ROTATE_DIGEST_CACHE:
opts->rotate_digest_cache = 1;
break;

View File

@ -27,7 +27,8 @@
#
# Define the ethernet interface on which we will sniff packets.
# Default if not set is eth0.
# Default if not set is eth0. The '-i <intf>' command line option overrides
# the PCAP_INTF setting.
#
#PCAP_INTF eth0;
@ -63,13 +64,13 @@
#
#ENABLE_DIGEST_PERSISTENCE Y;
# Sets the number of packets that are processed when the *pcap_dispatch()*
# call is made. The default is zero, since this allows *fwknopd* to process
# Sets the number of packets that are processed when the pcap_dispatch()
# call is made. The default is zero, since this allows fwknopd to process
# as many packets as possible in the corresponding callback where the SPA
# handling routine is called for packets that pass a set of prerequisite
# checks. However, if *fwknopd* is running on a platform with an old
# checks. However, if fwknopd is running on a platform with an old
# version of libpcap, it may be necessary to change this value to a positive
# non-zero integer. More information can be found in the *pcap_dispatch(3)*
# non-zero integer. More information can be found in the pcap_dispatch(3)
# man page.
#PCAP_DISPATCH_COUNT 0;
@ -121,6 +122,12 @@
#SYSLOG_IDENTITY fwknopd;
#SYSLOG_FACILITY LOG_DAEMON;
# Define this to have fwknopd read pcap data from a file instead of sniffing
# a live interface. This is usually only used for debugging purposes, and is
# equivalent to the '-r <pcap file>' command line option.
#
#PCAP_FILE /some/path/to/file.pcap;
##############################################################################
# NOTE: The following EXTERNAL_CMD functionality is not yet implemented.
# This is a possible future feature of fwknopd.

View File

@ -165,6 +165,7 @@ enum {
CONF_OVERRIDE_CONFIG,
//CONF_FIREWALL_TYPE,
CONF_PCAP_INTF,
CONF_PCAP_FILE,
CONF_ENABLE_PCAP_PROMISC,
CONF_PCAP_FILTER,
CONF_PCAP_DISPATCH_COUNT,

View File

@ -254,7 +254,7 @@ incoming_spa(fko_srv_options_t *opts)
char *spa_ip_demark, *gpg_id, *raw_digest = NULL;
time_t now_ts;
int res, status, ts_diff, enc_type, stanza_num=0;
int added_replay_digest = 0;
int added_replay_digest = 0, pkt_data_len=0;
spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);
@ -273,6 +273,7 @@ incoming_spa(fko_srv_options_t *opts)
* SPA data and/or to be reasonably sure we have a SPA packet (i.e
* try to eliminate obvious non-spa packets).
*/
pkt_data_len = spa_pkt->packet_data_len;
res = preprocess_spa_data(opts, spadat.pkt_source_ip);
if(res != FKO_SUCCESS)
{
@ -282,6 +283,12 @@ incoming_spa(fko_srv_options_t *opts)
return;
}
if(opts->foreground == 1 && opts->verbose > 2)
{
printf("[+] candidate SPA packet payload:\n");
hex_dump(spa_pkt->packet_data, pkt_data_len);
}
if (is_src_match(opts->acc_stanzas, ntohl(spa_pkt->packet_src_ip)))
{
if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)

View File

@ -57,6 +57,7 @@ pcap_capture(fko_srv_options_t *opts)
int pending_break = 0;
int promisc = 0;
int set_direction = 1;
int pcap_file_mode = 0;
int status;
int useconds;
pid_t child_pid;
@ -72,25 +73,39 @@ pcap_capture(fko_srv_options_t *opts)
if(opts->config[CONF_ENABLE_PCAP_PROMISC][0] == 'Y')
promisc = 1;
log_msg(LOG_INFO, "Sniffing interface: %s",
opts->config[CONF_PCAP_INTF]);
if(opts->config[CONF_PCAP_FILE] != NULL
&& opts->config[CONF_PCAP_FILE][0] != '\0')
pcap_file_mode = 1;
pcap = pcap_open_live(
opts->config[CONF_PCAP_INTF],
atoi(opts->config[CONF_MAX_SNIFF_BYTES]),
promisc, 100, errstr
);
if(pcap_file_mode == 1) {
log_msg(LOG_INFO, "Reading pcap file: %s",
opts->config[CONF_PCAP_FILE]);
if(pcap == NULL)
{
log_msg(LOG_ERR, "[*] pcap_open_live error: %s\n", errstr);
clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
pcap = pcap_open_offline(opts->config[CONF_PCAP_FILE], errstr);
if(pcap == NULL)
{
log_msg(LOG_ERR, "[*] pcap_open_offline() error: %s\n",
errstr);
clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
}
}
if (pcap == NULL)
else
{
log_msg(LOG_ERR, "[*] pcap error: %s", errstr);
clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
log_msg(LOG_INFO, "Sniffing interface: %s",
opts->config[CONF_PCAP_INTF]);
pcap = pcap_open_live(
opts->config[CONF_PCAP_INTF],
atoi(opts->config[CONF_MAX_SNIFF_BYTES]),
promisc, 100, errstr
);
if(pcap == NULL)
{
log_msg(LOG_ERR, "[*] pcap_open_live() error: %s\n", errstr);
clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
}
}
/* Set pcap filters, if any.
@ -144,7 +159,8 @@ pcap_capture(fko_srv_options_t *opts)
/* We are only interested on seeing packets coming into the interface.
*/
if (set_direction && (pcap_setdirection(pcap, PCAP_D_IN) < 0))
if (set_direction && (pcap_file_mode == 0)
&& (pcap_setdirection(pcap, PCAP_D_IN) < 0))
if(opts->verbose)
log_msg(LOG_WARNING, "[*] Warning: pcap error on setdirection: %s.",
pcap_geterr(pcap));
@ -153,7 +169,7 @@ pcap_capture(fko_srv_options_t *opts)
*
* NOTE: This is simply set to 0 for now until we find a need
* to actually use this mode (which when set on a FreeBSD
* system, it silently breaks the packet capture).
* system, it silently breaks the packet capture).
*/
if((pcap_setnonblock(pcap, DEF_PCAP_NONBLOCK, errstr)) == -1)
{
@ -233,6 +249,9 @@ pcap_capture(fko_srv_options_t *opts)
*/
if(res > 0)
{
if(opts->foreground == 1 && opts->verbose > 2)
log_msg(LOG_INFO, "pcap_dispatch() processed: %d packets", res);
/* Count the set of processed packets (pcap_dispatch() return
* value) - we use this as a comparison for --packet-limit regardless
* of SPA packet validity at this point.

BIN
test/conf/spa_replay.pcap Normal file

Binary file not shown.

View File

@ -20,6 +20,7 @@ my $cmd_out_tmp = 'cmd.out';
my $server_cmd_tmp = 'server_cmd.out';
my $gpg_client_home_dir = "$conf_dir/client-gpg";
my $gpg_client_home_dir_no_pw = "$conf_dir/client-gpg-no-pw";
my $replay_pcap_file = "$conf_dir/spa_replay.pcap";
my %cf = (
'nat' => "$conf_dir/nat_fwknopd.conf",
@ -129,6 +130,7 @@ my $NO = 0;
my $PRINT_LEN = 68;
my $USE_PREDEF_PKTS = 1;
my $USE_CLIENT = 2;
my $USE_PCAP_FILE = 3;
my $REQUIRED = 1;
my $OPTIONAL = 0;
my $NEW_RULE_REQUIRED = 1;
@ -1189,6 +1191,25 @@ my @tests = (
'fatal' => $NO
},
### --pcap-file
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
'detail' => '--pcap-file processing',
'err_msg' => 'could not complete SPA cycle',
'function' => \&process_pcap_file_directly,
'cmdline' => '',
'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " .
"$fwknopdCmd $default_server_conf_args " .
"--pcap-file $replay_pcap_file --foreground --verbose --verbose " .
"--verbose",
'server_positive_output_matches' => [qr/Replay\sdetected/i,
qr/candidate\sSPA/, qr/0x0000\:\s+2b/],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'fatal' => $NO
},
{
'category' => 'Rijndael SPA',
'subcategory' => 'client+server',
@ -4243,6 +4264,46 @@ sub altered_non_base64_spa_data() {
return $rv;
}
sub process_pcap_file_directly() {
my $test_hr = shift;
my $rv = 1;
my $server_was_stopped = 0;
my $fw_rule_created = 0;
my $fw_rule_removed = 0;
($rv, $server_was_stopped, $fw_rule_created, $fw_rule_removed)
= &client_server_interaction($test_hr, [], $USE_PCAP_FILE);
$rv = 0 unless $server_was_stopped;
if ($test_hr->{'fw_rule_created'} eq $NEW_RULE_REQUIRED) {
$rv = 0 unless $fw_rule_created;
} elsif ($test_hr->{'fw_rule_created'} eq $REQUIRE_NO_NEW_RULE) {
$rv = 0 if $fw_rule_created;
}
if ($test_hr->{'fw_rule_removed'} eq $NEW_RULE_REMOVED) {
$rv = 0 unless $fw_rule_removed;
} elsif ($test_hr->{'fw_rule_removed'} eq $REQUIRE_NO_NEW_REMOVED) {
$rv = 0 if $fw_rule_removed;
}
if ($test_hr->{'server_positive_output_matches'}) {
$rv = 0 unless &file_find_regex(
$test_hr->{'server_positive_output_matches'},
$MATCH_ALL, $server_test_file);
}
if ($test_hr->{'server_negative_output_matches'}) {
$rv = 0 if &file_find_regex(
$test_hr->{'server_negative_output_matches'},
$MATCH_ANY, $server_test_file);
}
return $rv;
}
sub fuzzer() {
my $test_hr = shift;
@ -4552,8 +4613,10 @@ sub client_server_interaction() {
$current_test_file);
$rv = 0;
}
} else {
} elsif ($spa_client_flag == $USE_PREDEF_PKTS) {
&send_packets($pkts_hr);
} else {
### pcap file mode, nothing to do
}
### check to see if the SPA packet resulted in a new fw access rule

View File

@ -2,6 +2,11 @@
This is the main todo org mode file for the fwknop project
** COMPLETED
This bucket is for completed tasks.
*** [server] Add the ability to process pcap files offline
:CLOSED: <2012-11-08 Thu>
Leverage pcap_open_offline() to process pcap files from disk instead of
sniffing the network live.
- Added a new '--pcap-file <file>' option for this purpose.
*** Add --disable-gpg arg to the autoconf configure script
:CLOSED: <2012-10-31 Wed>
There needs to be a way to easily disable libgpgme usage even if it is
@ -48,9 +53,6 @@
:CLOSED: <2012-10-02 Tue>
The access.c parsing code currently throws an error if there is not KEY
variable in an access stanza even if GPG_ALLOW_NO_PW is set.
** [server] Add the ability to process pcap files offline
Leverage pcap_open_offline() to process pcap files from disk instead of
sniffing the network live.
** [server] Add PF NAT support for OpenBSD systems
fwknopd already supports various NAT modes on iptables, but it should be
extended to support NAT on PF firewalls.