[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:
parent
7afe5b28b7
commit
66ad134708
@ -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
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'},
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
BIN
test/conf/spa_replay.pcap
Normal file
Binary file not shown.
@ -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
|
||||
|
||||
8
todo.org
8
todo.org
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user