Added support for FWKNOP_OUTPUT_ACCESS and NAT_ACCESS modes (still needs testing and tweaking).

git-svn-id: file:///home/mbr/svn/fwknop/trunk@216 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
Damien Stuart
2010-06-15 02:50:17 +00:00
parent fa12602f09
commit 579ec77698
5 changed files with 298 additions and 99 deletions
+10 -1
View File
@@ -73,7 +73,16 @@
#
# This specifies whether or not fwknopd will accept complete commands that
# are contained within a SPA packet. Any such command will be executed as
# root by the fwknopd server. If not set here, the default is "N".
# user specified using the CMD_EXEC_USER parameter by the fwknopd server.
# If not set here, the default is "N".
#
# CMD_EXEC_USER: <username>;
#
# This specifies the user that will execute commands contained within a SPA
# packet. If not specified, fwknopd will execute it as the user it is
# running as (most likely root). Setting this to a non-root user is highly
# recommended.
#
# CMD_REGEX: <regex>; **NOT YET SUPPORTED**
+211 -23
View File
@@ -137,7 +137,7 @@ delete_all_chains(void)
char cmd_buf[CMD_BUFSIZE] = {0};
char err[CMD_BUFSIZE] = {0};
for(i=0; i<(NUM_FWKNOP_CHAIN_TYPES-1); i++)
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES-1); i++)
{
if(fwc.chain[i].target[0] == '\0')
continue;
@@ -193,7 +193,7 @@ create_fw_chains(void)
char cmd_buf[CMD_BUFSIZE] = {0};
char err[CMD_BUFSIZE] = {0};
for(i=0; i<(NUM_FWKNOP_CHAIN_TYPES-1); i++)
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES-1); i++)
{
if(fwc.chain[i].target[0] == '\0')
continue;
@@ -339,20 +339,51 @@ fw_initialize(fko_srv_options_t *opts)
exit(EXIT_FAILURE);
}
if(opts->config[CONF_IPT_OUTPUT_ACCESS] != NULL)
/* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y
*/
if(opts->config[CONF_ENABLE_IPT_OUTPUT] != NULL
&& (strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0)
&& opts->config[CONF_IPT_OUTPUT_ACCESS] != NULL)
set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]);
if(opts->config[CONF_IPT_FORWARD_ACCESS] != NULL)
set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]);
/* The remaining access chains require ENABLE_IPT_FORWARDING = Y
*/
if(opts->config[CONF_ENABLE_IPT_FORWARDING] != NULL
&& (strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0))
{
if(opts->config[CONF_IPT_DNAT_ACCESS] != NULL)
set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]);
if(opts->config[CONF_IPT_FORWARD_ACCESS] != NULL)
set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]);
if(opts->config[CONF_IPT_SNAT_ACCESS] != NULL)
set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]);
if(opts->config[CONF_IPT_DNAT_ACCESS] != NULL)
set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]);
if(opts->config[CONF_IPT_MASQUERADE_ACCESS] != NULL)
set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]);
/* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y
*/
if(opts->config[CONF_ENABLE_IPT_SNAT] != NULL
&& (strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0))
{
/* If an SNAT_TRANSLATE_IP is specified use the SNAT_ACCESS mode.
* Otherwise, use MASQUERADE_ACCESS.
*
* XXX: --DSS: Not sure if using the TRANSLATE_IP parameter as
* the determining factor is the best why to handle
* this.
*
*/
if(opts->config[CONF_ENABLE_IPT_SNAT] != NULL
&& strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "_CHANGE_ME_", 11)!=0)
{
if(opts->config[CONF_IPT_SNAT_ACCESS] != NULL)
set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]);
}
else
{
if(opts->config[CONF_IPT_MASQUERADE_ACCESS] != NULL)
set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]);
}
}
}
/* Let us find it via our opts struct as well.
*/
@@ -388,13 +419,22 @@ process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
{
char cmd_buf[CMD_BUFSIZE] = {0};
char err[CMD_BUFSIZE] = {0};
char nat_ip[16] = {0};
char *ndx;
unsigned int nat_port = 0;;
acc_port_list_t *port_list = NULL;
acc_port_list_t *ple;
unsigned int cproto;
unsigned int cport;
struct fw_chain *chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);
struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);
struct fw_chain *out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]);
struct fw_chain *fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]);
struct fw_chain *dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]);
struct fw_chain *snat_chain; // We assign this later (when we get it done)
int status, res;
time_t now, exp_ts;
@@ -406,54 +446,202 @@ process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
/* Create an access command for each proto/port for the source ip.
*/
ple = port_list;
cproto = ple->proto;
cport = ple->port;
while(ple != NULL)
{
time(&now);
exp_ts = now + spadat->fw_access_timeout;
memset(cmd_buf, 0x0, CMD_BUFSIZE);
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
opts->fw_config->fw_command,
chain->table,
chain->to_chain,
in_chain->table,
in_chain->to_chain,
ple->proto,
spadat->use_src_ip,
ple->port,
exp_ts,
chain->target
in_chain->target
);
//--DSS tmp
//fprintf(stderr, "ADD CMD: %s", cmd_buf);
//fprintf(stderr, "ADD CMD: %s\n", cmd_buf);
res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status);
if(EXTCMD_IS_SUCCESS(res))
{
log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
chain->to_chain, spadat->use_src_ip,
in_chain->to_chain, spadat->use_src_ip,
spadat->spa_message_remain, exp_ts
);
chain->active_rules++;
in_chain->active_rules++;
/* Reset the next expected expire time for this chain if it
* is warranted.
*/
if(chain->next_expire < now || exp_ts < chain->next_expire)
chain->next_expire = exp_ts;
if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
in_chain->next_expire = exp_ts;
}
else
parse_extcmd_error(res, status, err);
/* If we have to make an corresponding OUTPUT rule if out_chain target
* is not NULL.
*/
if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
{
memset(cmd_buf, 0x0, CMD_BUFSIZE);
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_OUT_RULE_ARGS,
opts->fw_config->fw_command,
out_chain->table,
out_chain->to_chain,
ple->proto,
spadat->use_src_ip,
ple->port,
exp_ts,
out_chain->target
);
//--DSS tmp
//fprintf(stderr, "ADD OUTPUT CMD: %s\n", cmd_buf);
res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status);
if(EXTCMD_IS_SUCCESS(res))
{
log_msg(LOG_INFO, "Added OUTPUT Rule to %s for %s, %s expires at %u",
out_chain->to_chain, spadat->use_src_ip,
spadat->spa_message_remain, exp_ts
);
out_chain->active_rules++;
/* Reset the next expected expire time for this chain if it
* is warranted.
*/
if(out_chain->next_expire < now || exp_ts < out_chain->next_expire)
out_chain->next_expire = exp_ts;
}
else
parse_extcmd_error(res, status, err);
}
ple = ple->next;
}
/* Done with the port list.
/* Done with the port list for access rules.
*/
free_acc_port_list(port_list);
/* Now see if we have NAT rules to create...
*/
if( spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
|| spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
|| spadat->message_type == FKO_NAT_ACCESS_MSG
|| spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG )
{
/* Parse out the NAT IP and Port components.
*/
ndx = strchr(spadat->nat_access, ',');
if(ndx != NULL)
{
strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1);
nat_port = atoi(ndx+1);
}
// --DSS temp
//fprintf(stderr, "NAT IP: '%s', NAT PORT: '%i'\n", nat_ip, nat_port);
/* Make our FORWARD and NAT rules
*/
if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
{
memset(cmd_buf, 0x0, CMD_BUFSIZE);
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_FWD_RULE_ARGS,
opts->fw_config->fw_command,
fwd_chain->table,
fwd_chain->to_chain,
cproto,
spadat->use_src_ip,
nat_ip,
nat_port,
exp_ts,
fwd_chain->target
);
//--DSS tmp
//fprintf(stderr, "ADD OUTPUT CMD: %s\n", cmd_buf);
res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status);
if(EXTCMD_IS_SUCCESS(res))
{
log_msg(LOG_INFO, "Added FORWARD Rule to %s for %s, %s expires at %u",
fwd_chain->to_chain, spadat->use_src_ip,
spadat->spa_message_remain, exp_ts
);
fwd_chain->active_rules++;
/* Reset the next expected expire time for this chain if it
* is warranted.
*/
if(fwd_chain->next_expire < now || exp_ts < fwd_chain->next_expire)
fwd_chain->next_expire = exp_ts;
}
else
parse_extcmd_error(res, status, err);
}
if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
{
memset(cmd_buf, 0x0, CMD_BUFSIZE);
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_DNAT_RULE_ARGS,
opts->fw_config->fw_command,
dnat_chain->table,
dnat_chain->to_chain,
cproto,
spadat->use_src_ip,
cport,
exp_ts,
dnat_chain->target,
nat_ip,
nat_port
);
//--DSS tmp
//fprintf(stderr, "ADD DNAT CMD: %s\n", cmd_buf);
res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status);
if(EXTCMD_IS_SUCCESS(res))
{
log_msg(LOG_INFO, "Added DNAT Rule to %s for %s, %s expires at %u",
dnat_chain->to_chain, spadat->use_src_ip,
spadat->spa_message_remain, exp_ts
);
dnat_chain->active_rules++;
/* Reset the next expected expire time for this chain if it
* is warranted.
*/
if(dnat_chain->next_expire < now || exp_ts < dnat_chain->next_expire)
dnat_chain->next_expire = exp_ts;
}
else
parse_extcmd_error(res, status, err);
}
}
return(res);
}
/* Iterate over the configure firewall access chains and purge expired
* firewall rules.
*/
void
check_firewall_rules(fko_srv_options_t *opts)
{
@@ -473,7 +661,7 @@ check_firewall_rules(fko_srv_options_t *opts)
/* Iterate over each chain and look for active rules to delete.
*/
for(i = 0; i < NUM_FWKNOP_CHAIN_TYPES; i++)
for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
{
/* Just in case we somehow lose track and fall out-of-whack.
*/
+3
View File
@@ -34,6 +34,9 @@
/* iptables command args
*/
#define IPT_ADD_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -m comment --comment _exp_%u -j %s"
#define IPT_ADD_OUT_RULE_ARGS "-t %s -A %s -p %i -d %s --sport %i -m comment --comment _exp_%u -j %s"
#define IPT_ADD_FWD_RULE_ARGS "-t %s -A %s -p %i -s %s -d %s --dport %i -m comment --comment _exp_%u -j %s"
#define IPT_ADD_DNAT_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -m comment --comment _exp_%u -j %s --to-destination %s:%i"
#define IPT_DEL_RULE_ARGS "-t %s -D %s %i"
#define IPT_NEW_CHAIN_ARGS "-t %s -N %s"
#define IPT_FLUSH_CHAIN_ARGS "-t %s -F %s"
+3 -3
View File
@@ -340,7 +340,7 @@ enum {
IPT_DNAT_ACCESS,
IPT_SNAT_ACCESS,
IPT_MASQUERADE_ACCESS,
NUM_FWKNOP_CHAIN_TYPES /* Leave this entry last */
NUM_FWKNOP_ACCESS_TYPES /* Leave this entry last */
};
#define FW_CHAIN_DIR_SRC_STR "src"
@@ -376,7 +376,7 @@ struct fw_chain {
#define FW_NUM_CHAIN_FIELDS 7
struct fw_config {
struct fw_chain chain[NUM_FWKNOP_CHAIN_TYPES];
struct fw_chain chain[NUM_FWKNOP_ACCESS_TYPES];
char fw_command[MAX_PATH_LEN];
};
@@ -400,7 +400,7 @@ typedef struct spa_data
char *spa_message;
char spa_message_src_ip[16];
char pkt_source_ip[16];
char spa_message_remain[1024]; /* --DSS arbitrary bounds */
char spa_message_remain[1024]; /* --DSS FIXME: arbitrary bounds */
char *nat_access;
char *server_auth;
unsigned int client_timeout;
+71 -72
View File
@@ -281,7 +281,7 @@ incoming_spa(fko_srv_options_t *opts)
goto clean_and_bail;
}
strlcpy(spadat.spa_message_src_ip, spadat.spa_message, (spa_ip_demark - spadat.spa_message) + 1);
strlcpy(spadat.spa_message_src_ip, spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);
strlcpy(spadat.spa_message_remain, spa_ip_demark+1, 1024);
/* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
@@ -319,87 +319,86 @@ incoming_spa(fko_srv_options_t *opts)
}
}
/* Take action based on SPA message type.
/* Take action based on SPA message type. */
/* Command messages.
*/
switch(spadat.message_type)
if(spadat.message_type == FKO_COMMAND_MSG)
{
/* Command messages.
*/
case FKO_COMMAND_MSG:
if(!acc->enable_cmd_exec)
{
log_msg(LOG_WARNING|LOG_STDERR,
"SPA Command message are not allowed in the current configuration."
);
res = SPA_MSG_ACCESS_DENIED;
}
else
{
/* --DSS TODO: Finish Me */
log_msg(LOG_WARNING|LOG_STDERR,
"SPA Command message are not yet supported."
);
res = SPA_MSG_NOT_SUPPORTED;
}
break;
/* NAT access messages.
*/
case FKO_NAT_ACCESS_MSG:
case FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG:
if(!acc->enable_cmd_exec)
{
log_msg(LOG_WARNING|LOG_STDERR,
"SPA NAT access messages are not yet supported."
"SPA Command message are not allowed in the current configuration."
);
res = SPA_MSG_ACCESS_DENIED;
}
else
{
/* --DSS TODO: Finish Me */
log_msg(LOG_WARNING|LOG_STDERR,
"SPA Command message are not yet supported."
);
res = SPA_MSG_NOT_SUPPORTED;
/* --DSS TODO: Finish Me */
break;
}
/* Local NAT access messages.
*/
case FKO_LOCAL_NAT_ACCESS_MSG:
case FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG:
log_msg(LOG_WARNING|LOG_STDERR,
"SPA Local NAT access messages are not yet supported."
);
res = SPA_MSG_NOT_SUPPORTED;
/* --DSS TODO: Finish Me */
break;
/* Standard access messages.
*/
case FKO_ACCESS_MSG:
case FKO_CLIENT_TIMEOUT_ACCESS_MSG:
/* Check access against restrict_ports and open_ports.
*/
res = acc_check_port_access(acc, spadat.spa_message_remain);
if(!res)
{
log_msg(LOG_WARNING|LOG_STDERR,
"One or more requested protocol/ports was denied per access.conf."
);
res = SPA_MSG_ACCESS_DENIED;
}
else
{
/* Process the access message.
*/
/* --DSS temp
log_msg(LOG_WARNING|LOG_STDERR,
"<<<< This SPA access msg would be %s >>>>",
res ? "allowed":"DENIED due to port restictions"
);
res = SPA_MSG_NOT_SUPPORTED;
*/
res = process_access_request(opts, &spadat);
}
break;
goto clean_and_bail;
}
/* Send to the firewall rule processor.
/* From this point forward, we have some kind of access message. So
* we first see if access is allowed by checking access against
* restrict_ports and open_ports.
*
* --DSS TODO: We should add BLACKLIST support here as well.
*/
// TODO: Finish me
if(! acc_check_port_access(acc, spadat.spa_message_remain))
{
log_msg(LOG_WARNING|LOG_STDERR,
"One or more requested protocol/ports was denied per access.conf."
);
res = SPA_MSG_ACCESS_DENIED;
goto clean_and_bail;
}
/* If we are here we will at least need to have the base access. So we
* can go ahead an generate that now.
*/
res = process_access_request(opts, &spadat);
#if 0
if(res != FKO_SUCCESS)
goto clean_and_bail;
/* Now see if we are looking for a local NAT access of some sort.
*/
if(spadat.message_type == FKO_LOCAL_NAT_ACCESS_MSG
|| spadat.message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
{
log_msg(LOG_WARNING|LOG_STDERR,
"SPA Local NAT access messages are not yet supported."
);
/* --DSS TODO: Finish Me */
res = SPA_MSG_NOT_SUPPORTED;
goto clean_and_bail;
}
/* NAT access messages.
*/
if(spadat.message_type == FKO_NAT_ACCESS_MSG
|| spadat.message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
{
log_msg(LOG_WARNING|LOG_STDERR,
"SPA NAT access messages are not yet supported."
);
res = SPA_MSG_NOT_SUPPORTED;
/* --DSS TODO: Finish Me */
}
#endif
clean_and_bail:
if(ctx != NULL)