- [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
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 \
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
"OVERRIDE_CONFIG",
//"FIREWALL_TYPE",
"PCAP_INTF",
+ "PCAP_FILE",
"ENABLE_PCAP_PROMISC",
"PCAP_FILTER",
"PCAP_DISPATCH_COUNT",
FW_LIST_ALL,
FW_FLUSH,
GPG_HOME_DIR,
+ PCAP_FILE,
ROTATE_DIGEST_CACHE,
NOOP /* Just to be a marker for the end */
};
{"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'},
/* 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);
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.
*/
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;
#
# 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;
#
#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;
#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.
CONF_OVERRIDE_CONFIG,
//CONF_FIREWALL_TYPE,
CONF_PCAP_INTF,
+ CONF_PCAP_FILE,
CONF_ENABLE_PCAP_PROMISC,
CONF_PCAP_FILTER,
CONF_PCAP_DISPATCH_COUNT,
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);
* 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)
{
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)
int pending_break = 0;
int promisc = 0;
int set_direction = 1;
+ int pcap_file_mode = 0;
int status;
int useconds;
pid_t child_pid;
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)
+ if(pcap == NULL)
+ {
+ log_msg(LOG_ERR, "[*] pcap_open_offline() error: %s\n",
+ errstr);
+ clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
+ }
+ }
+ 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.
/* 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));
*
* 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)
{
*/
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.
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",
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;
'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',
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;
$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
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
: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.