[server] Added FORCE_SNAT to access.conf stanzas.

Added FORCE_SNAT to the access.conf file so that per-access stanza SNAT
criteria can be specified for SPA access.
This commit is contained in:
Michael Rash
2013-12-04 21:52:07 -05:00
parent d7aa820e33
commit e0114e60c2
7 changed files with 144 additions and 30 deletions
+2
View File
@@ -29,6 +29,8 @@ fwknop-2.5.2 (//2013):
- [server] Bug fix for SPA NAT modes on iptables firewalls to ensure that
custom fwknop chains are re-created if they get deleted out from under
the running fwknopd instance.
- [server] Added FORCE_SNAT to the access.conf file so that per-access
stanza SNAT criteria can be specified for SPA access.
- [test suite] added --gdb-test to allow a previously executed fwknop
or fwknopd command to be sent through gdb with the same command line
args as the test suite used. This is for convenience to rapidly allow
+10
View File
@@ -443,6 +443,16 @@ directive starts a new stanza.
for each stanza in the access.conf file. This way, multiple external
users can each directly access only one internal system per SPA key.
*FORCE_SNAT* '<IP>'::
For any valid SPA packet, add an SNAT rule in addition to any DNAT rule
created with a corresponding (required) FORCE_NAT variable. This is
analogous to SNAT_TRANSLATE_IP from the '@sysconfdir@/fwknop/fwknopd.conf'' file
except that it is per access stanza and overrides any value set with
SNAT_TRANSLATE_IP. This is useful for situations where an incoming NAT'd
connection may be otherwise unanswerable due to routing constraints (i.e.
the system receiving the SPA authenticated connection has a default route
to a different device than the SPA system itself).
*GPG_HOME_DIR* '<path>'::
Define the path to the GnuPG directory to be used by the *fwknopd*
server. If this keyword is not specified within '@sysconfdir@/fwknop/access.conf' then
+56 -1
View File
@@ -165,7 +165,6 @@ add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *v
if (sscanf(val, "%15s %5u", ip_str, &curr_acc->force_nat_port) != 2)
{
log_msg(LOG_ERR,
"[*] Fatal: invalid FORCE_NAT arg '%s', need <IP> <PORT>",
val
@@ -192,6 +191,32 @@ add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *v
return;
}
static void
add_acc_force_snat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *val)
{
char ip_str[MAX_IPV4_STR_LEN] = {0};
if (sscanf(val, "%15s", ip_str) != 1)
{
log_msg(LOG_ERR,
"[*] Fatal: invalid FORCE_SNAT arg '%s', need <IP>", val);
clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
}
if(! is_valid_ipv4_addr(ip_str))
{
log_msg(LOG_ERR,
"[*] Fatal: invalid FORCE_NAT IP '%s'", ip_str);
clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
}
curr_acc->force_snat = 1;
add_acc_string(&(curr_acc->force_snat_ip), ip_str);
return;
}
#endif
/* Take an IP or Subnet/Mask and convert it to mask for later
@@ -680,6 +705,9 @@ free_acc_stanza_data(acc_stanza_t *acc)
if(acc->force_nat_ip != NULL)
free(acc->force_nat_ip);
if(acc->force_nat_ip != NULL)
free(acc->force_snat_ip);
if(acc->key != NULL)
{
zero_buf_wrapper(acc->key, acc->key_len);
@@ -955,6 +983,15 @@ acc_data_is_valid(acc_stanza_t * const acc)
}
}
if(acc->force_snat == 1 && acc->force_nat == 0)
{
log_msg(LOG_ERR,
"[*] FORCE_SNAT implies FORCE_NAT must also be used for access stanza source: '%s'",
acc->source
);
return(0);
}
if(acc->require_source_address == 0)
{
log_msg(LOG_INFO,
@@ -1338,6 +1375,24 @@ parse_access_file(fko_srv_options_t *opts)
"[*] FORCE_NAT not supported.");
fclose(file_ptr);
clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
#endif
}
else if(CONF_VAR_IS(var, "FORCE_SNAT"))
{
#if FIREWALL_IPTABLES
if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 )
{
log_msg(LOG_ERR,
"[*] FORCE_SNAT_NAT requires ENABLE_IPT_FORWARDING to be enabled in fwknopd.conf");
fclose(file_ptr);
clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
}
add_acc_force_snat(opts, curr_acc, val);
#else
log_msg(LOG_ERR,
"[*] FORCE_SNAT not supported.");
fclose(file_ptr);
clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE);
#endif
}
else
+21 -25
View File
@@ -961,7 +961,7 @@ process_spa_request(const fko_srv_options_t * const opts,
struct fw_chain * const dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]);
struct fw_chain *snat_chain; /* We assign this later (if we need to). */
int res = 0, is_err;
int res = 0, is_err, snat_chain_num = 0;
time_t now;
unsigned int exp_ts;
@@ -1260,29 +1260,27 @@ process_spa_request(const fko_srv_options_t * const opts,
/* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well.
*/
if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
{
/* Setup some parameter depending on whether we are using SNAT
* or MASQUERADE.
/* Add SNAT or MASQUERADE rules.
*/
if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL)
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
if(acc->force_snat && is_valid_ipv4_addr(acc->force_snat_ip))
{
/* Using static SNAT */
snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
"--to-source %s:%i", acc->force_snat_ip, fst_port);
snat_chain_num = IPT_SNAT_ACCESS;
}
else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL)
&& is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP]))
{
/* Using static SNAT */
snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
"--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
fst_port);
/* Check to make sure that the jump rules exist for each
* required chain
*/
if(chain_exists(opts, IPT_SNAT_ACCESS) == 0)
create_chain(opts, IPT_SNAT_ACCESS);
if(jump_rule_exists(opts, IPT_SNAT_ACCESS) == 0)
add_jump_rule(opts, IPT_SNAT_ACCESS);
snat_chain_num = IPT_SNAT_ACCESS;
}
else
{
@@ -1290,17 +1288,15 @@ process_spa_request(const fko_srv_options_t * const opts,
snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
"--to-ports %i", fst_port);
/* Check to make sure that the jump rules exist for each
* required chain
*/
if(chain_exists(opts, IPT_MASQUERADE_ACCESS) == 0)
create_chain(opts, IPT_MASQUERADE_ACCESS);
if(jump_rule_exists(opts, IPT_MASQUERADE_ACCESS) == 0)
add_jump_rule(opts, IPT_MASQUERADE_ACCESS);
snat_chain_num = IPT_MASQUERADE_ACCESS;
}
if(chain_exists(opts, snat_chain_num) == 0)
create_chain(opts, snat_chain_num);
if(jump_rule_exists(opts, snat_chain_num) == 0)
add_jump_rule(opts, snat_chain_num);
memset(rule_buf, 0, CMD_BUFSIZE);
snprintf(rule_buf, CMD_BUFSIZE-1, IPT_SNAT_RULE_ARGS,
+9
View File
@@ -321,10 +321,19 @@ typedef struct acc_stanza
time_t access_expire_time;
int expired;
int encryption_mode;
/* DNAT parameters
*/
unsigned char force_nat;
char *force_nat_ip;
char *force_nat_proto;
unsigned int force_nat_port;
/* SNAT parameters
*/
unsigned char force_snat;
char *force_snat_ip;
struct acc_stanza *next;
} acc_stanza_t;
+3
View File
@@ -79,6 +79,7 @@ our %cf = (
'invalid_ipt_input_chain6' => "$conf_dir/invalid_ipt_input_chain_6_fwknopd.conf",
'force_nat_access' => "$conf_dir/force_nat_access.conf",
'hmac_force_nat_access' => "$conf_dir/hmac_force_nat_access.conf",
'hmac_force_snat_access' => "$conf_dir/hmac_force_snat_access.conf",
'cmd_access' => "$conf_dir/cmd_access.conf",
'local_nat' => "$conf_dir/local_nat_fwknopd.conf",
'no_flush_init' => "$conf_dir/no_flush_init_fwknopd.conf",
@@ -186,6 +187,8 @@ our $fake_ip = '127.0.0.2';
our $spoof_ip = '1.2.3.4';
our $internal_nat_host = '192.168.1.2';
our $force_nat_host = '192.168.1.123';
our $force_nat_host2 = '123.4.4.4';
our $force_snat_host = '33.3.3.3';
our $default_spa_port = 62201;
our $non_std_spa_port = 12345;
+43 -4
View File
@@ -846,13 +846,52 @@
$cf{'rc_hmac_b64_key'},
'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'nat'} -a $cf{'hmac_force_nat_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/\sto\:$force_nat_host\:22/i],
'server_negative_output_matches' => [qr/\sto\:$internal_nat_host\:22/i],
'server_positive_output_matches' => [qr/\*\/\sto\:$force_nat_host\:22/i],
'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_conf' => $cf{'nat'},
'key_file' => $cf{'rc_hmac_b64_key'},
},
{
'category' => 'Rijndael+HMAC',
'subcategory' => 'client+server',
'detail' => "force SNAT $force_snat_host (tcp/22)",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'cmdline' => "$default_client_args_no_get_key --rc-file " .
$cf{'rc_hmac_b64_key'},
'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'snat'} -a $cf{'hmac_force_snat_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/DNAT\s.*\*\/\sto\:$force_nat_host2\:22/i,
qr/SNAT\s.*\*\/\sto\:$force_snat_host\:22/],
'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i,
qr/\*\/\sto\:$force_nat_host\:22/i],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_conf' => $cf{'snat'},
'key_file' => $cf{'rc_hmac_b64_key'},
},
{
'category' => 'Rijndael+HMAC',
'subcategory' => 'client+server',
'detail' => "force SNAT $force_snat_host (ipt flush)",
'function' => \&spa_cycle,
'cmdline' => $default_client_args,
'cmdline' => "$default_client_args_no_get_key --rc-file " .
$cf{'rc_hmac_b64_key'},
'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'snat'} -a $cf{'hmac_force_snat_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/DNAT\s.*\*\/\sto\:$force_nat_host2\:22/i,
qr/SNAT\s.*\*\/\sto\:$force_snat_host\:22/],
'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i,
qr/\*\/\sto\:$force_nat_host\:22/i],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_conf' => $cf{'snat'},
'key_file' => $cf{'rc_hmac_b64_key'},
'iptables_rm_chains_after_server_start' => $YES,
},
{
'category' => 'Rijndael+HMAC',
'subcategory' => 'client+server',
@@ -863,8 +902,8 @@
$cf{'rc_hmac_b64_key'},
'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'nat'} -a $cf{'hmac_force_nat_access'} " .
"-d $default_digest_file -p $default_pid_file $intf_str",
'server_positive_output_matches' => [qr/\sto\:$force_nat_host\:22/i],
'server_negative_output_matches' => [qr/\sto\:$internal_nat_host\:22/i],
'server_positive_output_matches' => [qr/\*\/\sto\:$force_nat_host\:22/i],
'server_negative_output_matches' => [qr/\*\/\sto\:$internal_nat_host\:22/i],
'fw_rule_created' => $NEW_RULE_REQUIRED,
'fw_rule_removed' => $NEW_RULE_REMOVED,
'server_conf' => $cf{'nat'},