diff --git a/CREDITS b/CREDITS index 5dc3fa2b..b9ebecd6 100644 --- a/CREDITS +++ b/CREDITS @@ -224,3 +224,9 @@ Dan Brooks - Contributed a patch for the Android client app to add the definition of custom server udp port. This is similiar to the --server-port argument offered by the main fwknop client. + +Github user 'sgh7': + - Contributed a patch to have fwknopd exit if the interface it is sniffing + on goes down. If this happens, it is expected that the native process + monitoring feature in things like systemd or upstart will restart + fwknopd. diff --git a/ChangeLog b/ChangeLog index 141b9d15..360dfce8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,14 @@ fwknop-2.6.7 (05//2015): Jonathan Bennett, and will help with ease of use efforts. The first platform to take advantage of this will likely be OpenWRT thanks to Jonathan. + - [server] By default, fwknopd will now exit if the interface that it is + sniffing goes down (patch contributed by Github user 'sgh7'). If this + happens, it is expected that the native process monitoring feature in + things like systemd or upstart will restart fwknopd. However, if fwknopd + is not being monitored by systemd, upstart, or anything else, this + behavior can be disabled with the EXIT_AT_INTF_DOWN variable in the + fwknopd.conf file. If disabled, fwknopd will try to recover when a + downed interface comes back up. - [extras] Added a script from Jonathan Bennett at extras/console-qr/console-qr.sh to generate QR codes from fwknopd access.conf keys. diff --git a/Makefile.am b/Makefile.am index 9b3781cd..306e3b09 100644 --- a/Makefile.am +++ b/Makefile.am @@ -151,6 +151,7 @@ EXTRA_DIST = \ test/conf/expired_epoch_stanza_access.conf \ test/conf/expired_stanza_access.conf \ test/conf/force_nat_access.conf \ + test/conf/no_exit_down_intf_fwknopd.conf \ test/conf/future_expired_stanza_access.conf \ test/conf/fuzzing_open_ports_access.conf \ test/conf/fuzzing_restrict_ports_access.conf \ diff --git a/doc/fwknopd.man.asciidoc b/doc/fwknopd.man.asciidoc index b56f9085..faa7d459 100644 --- a/doc/fwknopd.man.asciidoc +++ b/doc/fwknopd.man.asciidoc @@ -335,6 +335,15 @@ corresponding details. Flush all existing rules in the fwknop chains when *fwknopd* is stopped or otherwise exits cleanly. The default is ``Y''. +*EXIT_AT_INTF_DOWN* '':: + When *fwknopd* is sniffing an interface, if the interface is + administratively downed or unplugged, fwknopd will cleanly exit and an + assumption is made that any process monitoring infrastructure like systemd + or upstart will restart it. However, if fwknopd is not being monitored by + systemd, upstart, or anything else, this behavior can be disabled with the + ``EXIT_AT_INTF_DOWN'' variable. If disabled, fwknopd will try to recover + when a downed interface comes back up. + *GPG_HOME_DIR* '':: If GPG keys are used instead of a Rijndael symmetric key, this is the default GPG keys directory. Note that each access stanza in diff --git a/server/cmd_opts.h b/server/cmd_opts.h index 561a0198..cd39a7c1 100644 --- a/server/cmd_opts.h +++ b/server/cmd_opts.h @@ -48,6 +48,7 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { "PCAP_DISPATCH_COUNT", "PCAP_LOOP_SLEEP", "ENABLE_PCAP_ANY_DIRECTION", + "EXIT_AT_INTF_DOWN", "MAX_SNIFF_BYTES", "ENABLE_SPA_PACKET_AGING", "MAX_SPA_PACKET_AGE", diff --git a/server/config_init.c b/server/config_init.c index a1312549..d1456820 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -459,6 +459,13 @@ validate_options(fko_srv_options_t *opts) set_config_entry(opts, CONF_PCAP_LOOP_SLEEP, DEF_PCAP_LOOP_SLEEP); + /* Control whether to exit if the interface where we're sniffing + * goes down. + */ + if(opts->config[CONF_EXIT_AT_INTF_DOWN] == NULL) + set_config_entry(opts, CONF_EXIT_AT_INTF_DOWN, + DEF_EXIT_AT_INTF_DOWN); + /* PCAP Filter. */ if(opts->config[CONF_PCAP_FILTER] == NULL) diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 505b341c..2fdc2ae2 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -88,6 +88,7 @@ #define DEF_PCAP_DISPATCH_COUNT "100" #define DEF_PCAP_LOOP_SLEEP "100000" /* a tenth of a second (in microseconds) */ #define DEF_ENABLE_PCAP_ANY_DIRECTION "N" +#define DEF_EXIT_AT_INTF_DOWN "Y" #define DEF_ENABLE_SPA_PACKET_AGING "Y" #define DEF_MAX_SPA_PACKET_AGE "120" #define DEF_ENABLE_DIGEST_PERSISTENCE "Y" @@ -233,6 +234,7 @@ enum { CONF_PCAP_DISPATCH_COUNT, CONF_PCAP_LOOP_SLEEP, CONF_ENABLE_PCAP_ANY_DIRECTION, + CONF_EXIT_AT_INTF_DOWN, CONF_MAX_SNIFF_BYTES, CONF_ENABLE_SPA_PACKET_AGING, CONF_MAX_SPA_PACKET_AGE, diff --git a/server/pcap_capture.c b/server/pcap_capture.c index aff9d314..38d91e3d 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -299,7 +299,8 @@ pcap_capture(fko_srv_options_t *opts) */ else if(res == -1) { - if(errno == ENETDOWN) + if((strncasecmp(opts->config[CONF_EXIT_AT_INTF_DOWN], "Y", 1) == 0) + && errno == ENETDOWN) { log_msg(LOG_ERR, "[*] Fatal error from pcap_dispatch: %s", pcap_geterr(pcap) diff --git a/test/conf/no_exit_down_intf_fwknopd.conf b/test/conf/no_exit_down_intf_fwknopd.conf new file mode 100644 index 00000000..cac6a28d --- /dev/null +++ b/test/conf/no_exit_down_intf_fwknopd.conf @@ -0,0 +1 @@ +EXIT_AT_INTF_DOWN N; diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index 3e53e3b0..323d0286 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -276,6 +276,7 @@ our $openssl_path = ''; our $base64_path = ''; our $pinentry_fail = 0; our $perl_path = ''; +our $ifconfig_path = ''; our $platform = ''; our $help = 0; our $YES = 1; @@ -463,6 +464,7 @@ our %cf = ( 'dual_key_access' => "$conf_dir/dual_key_usage_access.conf", 'dual_key_legacy_iv_access' => "$conf_dir/dual_key_legacy_iv_access.conf", 'hmac_dual_key_access' => "$conf_dir/hmac_dual_key_usage_access.conf", + 'no_exit_down_intf' => "$conf_dir/no_exit_down_intf_fwknopd.conf", 'gpg_access' => "$conf_dir/gpg_access.conf", 'gpg_hmac_access' => "$conf_dir/gpg_hmac_access.conf", 'gpg_invalid_exe_access' => "$conf_dir/gpg_invalid_exe_access.conf", @@ -603,6 +605,7 @@ exit &diff_test_results() if $diff_mode; ### run an fwknop command under gdb from a previous test run exit &gdb_test_cmd() if $gdb_test_file; +$ifconfig_path = &find_command('ifconfig') unless $ifconfig_path; &identify_loopback_intf() unless $list_mode or $client_only_mode; ### make sure everything looks as expected before continuing @@ -901,6 +904,7 @@ my %test_keys = ( 'cmd_exec_file_owner' => $OPTIONAL, 'rm_rule_mid_cycle' => $OPTIONAL, 'server_receive_re' => $OPTIONAL, + 'no_exit_intf_down' => $OPTIONAL, 'positive_output_matches' => $OPTIONAL, 'negative_output_matches' => $OPTIONAL, 'client_and_server_mode' => $OPTIONAL_NUMERIC, @@ -5438,6 +5442,27 @@ sub server_ignore_small_packets() { return $rv; } +sub down_interface() { + my $test_hr = shift; + + my $rv = 1; + + &start_fwknopd($test_hr); + + &run_cmd("$ifconfig_path lo down", $cmd_out_tmp, $curr_test_file); + sleep 1; + &run_cmd("$ifconfig_path lo up", $cmd_out_tmp, $curr_test_file); + + if (&is_fwknopd_running()) { + $rv = 0 unless $test_hr->{'no_exit_intf_down'} eq $YES; + &stop_fwknopd(); + } + + $rv = 0 unless &process_output_matches($test_hr); + + return $rv; +} + sub client_server_interaction() { my ($test_hr, $pkts_hr, $spa_client_flag) = @_; @@ -6911,12 +6936,12 @@ sub init() { push @tests_to_exclude, qr/perl FKO module.*FUZZING/; } - $sudo_path = &find_command('sudo') unless $sudo_path; - $killall_path = &find_command('killall') unless $killall_path; - $pgrep_path = &find_command('pgrep') unless $pgrep_path; - $lib_view_cmd = &find_command('ldd') unless $lib_view_cmd; - $git_path = &find_command('git') unless $git_path; - $perl_path = &find_command('perl') unless $perl_path; + $sudo_path = &find_command('sudo') unless $sudo_path; + $killall_path = &find_command('killall') unless $killall_path; + $pgrep_path = &find_command('pgrep') unless $pgrep_path; + $lib_view_cmd = &find_command('ldd') unless $lib_view_cmd; + $git_path = &find_command('git') unless $git_path; + $perl_path = &find_command('perl') unless $perl_path; if ($sudo_path) { $username = (getpwuid((stat($test_suite_path))[4]))[0]; @@ -6949,6 +6974,10 @@ sub init() { $lcov_path = &find_command('lcov') unless $lcov_path; $genhtml_path = &find_command('genhtml') unless $genhtml_path; + unless ($ifconfig_path) { + push @tests_to_exclude, qr/down interface/; + } + ### see if we're compiled with ASAN support if (&file_find_regex([qr/enable\-asan\-support/], $MATCH_ALL, $NO_APPEND_RESULTS, $config_log)) { @@ -7154,6 +7183,9 @@ sub openssl_hmac_style_check() { sub identify_loopback_intf() { return if $loopback_intf; + die "[*] ifconfig command not found, use --loopback " + unless $ifconfig_path; + ### Linux: ### lo Link encap:Local Loopback @@ -7177,7 +7209,7 @@ sub identify_loopback_intf() { my $intf = ''; my $found_loopback_intf = 0; - my $cmd = 'ifconfig -a'; + my $cmd = "$ifconfig_path -a"; open C, "$cmd |" or die "[*] (use --loopback ) $cmd: $!"; while () { if (/^(\S+?):?\s+.*loopback/i) { diff --git a/test/tests/basic_operations.pl b/test/tests/basic_operations.pl index a2246581..0a1f8415 100644 --- a/test/tests/basic_operations.pl +++ b/test/tests/basic_operations.pl @@ -62,6 +62,26 @@ 'detail' => 'start restart stop cycle', 'function' => \&server_start_stop_cycle, }, + { + 'category' => 'basic operations', + 'subcategory' => 'server', + 'detail' => 'exit upon down interface', + 'function' => \&down_interface, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'def'} -a $cf{'hmac_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'server_positive_output_matches' => [qr/Fatal error from pcap_dispatch\b/], + }, + { + 'category' => 'basic operations', + 'subcategory' => 'server', + 'detail' => 'no exit upon down interface', + 'function' => \&down_interface, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'no_exit_down_intf'} " . + "-a $cf{'hmac_access'} -d $default_digest_file -p " . + "$default_pid_file $intf_str", + 'server_positive_output_matches' => [qr/Error from pcap_dispatch\b/], + 'no_exit_intf_down' => $YES + }, { 'category' => 'basic operations',