Tweaked firewall rule creation code. Added SNAT/MASQUERADE support. Fixed rule processing code so an INPUT rule was not created for NAT request. Still needs more review and testing.

git-svn-id: file:///home/mbr/svn/fwknop/trunk@217 510a4753-2344-4c79-9c09-4d669213fbeb
This commit is contained in:
Damien Stuart
2010-06-16 03:12:00 +00:00
parent 579ec77698
commit dc6058d3a5
4 changed files with 215 additions and 113 deletions
+159 -80
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_ACCESS_TYPES-1); i++)
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); 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_ACCESS_TYPES-1); i++)
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
{
if(fwc.chain[i].target[0] == '\0')
continue;
@@ -206,7 +206,7 @@ create_fw_chains(void)
fwc.chain[i].to_chain
);
//printf("CMD: '%s'\n", cmd_buf);
//printf("(%i) CMD: '%s'\n", i, cmd_buf);
res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status);
/* Expect full success on this */
if(! EXTCMD_IS_SUCCESS(res))
@@ -227,7 +227,7 @@ create_fw_chains(void)
fwc.chain[i].to_chain
);
//printf("CMD: '%s'\n", cmd_buf);
//printf("(%i) CMD: '%s'\n", i, cmd_buf);
res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status);
/* Expect full success on this */
if(! EXTCMD_IS_SUCCESS(res))
@@ -371,8 +371,8 @@ fw_initialize(fko_srv_options_t *opts)
* this.
*
*/
if(opts->config[CONF_ENABLE_IPT_SNAT] != NULL
&& strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "_CHANGE_ME_", 11)!=0)
if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "_CHANGEME_", 10)!=0)
{
if(opts->config[CONF_IPT_SNAT_ACCESS] != NULL)
set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]);
@@ -415,11 +415,12 @@ fw_cleanup(void)
/* Rule Processing - Create an access request...
*/
int
process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
process_spa_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 snat_target[SNAT_TARGET_BUFSIZE] = {0};
char *ndx;
unsigned int nat_port = 0;;
@@ -427,14 +428,14 @@ process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
acc_port_list_t *port_list = NULL;
acc_port_list_t *ple;
unsigned int cproto;
unsigned int cport;
unsigned int fst_proto;
unsigned int fst_port;
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 *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)
struct fw_chain *snat_chain; /* We assign this later (if we need to). */
int status, res;
time_t now, exp_ts;
@@ -443,103 +444,116 @@ process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
*/
expand_acc_port_list(&port_list, spadat->spa_message_remain);
/* Create an access command for each proto/port for the source ip.
/* Start at the top of the proto-port list...
*/
ple = port_list;
cproto = ple->proto;
cport = ple->port;
/* Remember the first proto/port combo in case we need them
* for NAT access requests.
*/
fst_proto = ple->proto;
fst_port = ple->port;
while(ple != NULL)
/* Set our expire time value.
*/
time(&now);
exp_ts = now + spadat->fw_access_timeout;
/* For straight access requests, we currently support multiple proto/port
* request.
*/
if(spadat->message_type == FKO_ACCESS_MSG
|| spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG)
{
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,
in_chain->table,
in_chain->to_chain,
ple->proto,
spadat->use_src_ip,
ple->port,
exp_ts,
in_chain->target
);
//--DSS tmp
//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",
in_chain->to_chain, spadat->use_src_ip,
spadat->spa_message_remain, exp_ts
);
in_chain->active_rules++;
/* Reset the next expected expire time for this chain if it
* is warranted.
*/
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.
/* Create an access command for each proto/port for the source ip.
*/
if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
while(ple != NULL)
{
memset(cmd_buf, 0x0, CMD_BUFSIZE);
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_OUT_RULE_ARGS,
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
opts->fw_config->fw_command,
out_chain->table,
out_chain->to_chain,
in_chain->table,
in_chain->to_chain,
ple->proto,
spadat->use_src_ip,
ple->port,
exp_ts,
out_chain->target
in_chain->target
);
//--DSS tmp
//fprintf(stderr, "ADD OUTPUT CMD: %s\n", 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 OUTPUT Rule to %s for %s, %s expires at %u",
out_chain->to_chain, spadat->use_src_ip,
log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
in_chain->to_chain, spadat->use_src_ip,
spadat->spa_message_remain, exp_ts
);
out_chain->active_rules++;
in_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;
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;
}
ple = ple->next;
/* Done with the port list for access rules.
*/
free_acc_port_list(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
/* NAT requests... */
else 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 )
@@ -566,7 +580,7 @@ process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
opts->fw_config->fw_command,
fwd_chain->table,
fwd_chain->to_chain,
cproto,
fst_proto,
spadat->use_src_ip,
nat_ip,
nat_port,
@@ -604,9 +618,9 @@ process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
opts->fw_config->fw_command,
dnat_chain->table,
dnat_chain->to_chain,
cproto,
fst_proto,
spadat->use_src_ip,
cport,
fst_port,
exp_ts,
dnat_chain->target,
nat_ip,
@@ -634,6 +648,69 @@ process_access_request(fko_srv_options_t *opts, spa_data_t *spadat)
else
parse_extcmd_error(res, status, err);
}
/* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well.
*/
if(opts->config[CONF_ENABLE_IPT_SNAT] != NULL
&& strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
{
memset(cmd_buf, 0x0, CMD_BUFSIZE);
/* Setup some parameter depending on whether we are using SNAT
* or MASQUERADE.
*/
if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "_CHANGEME_", 10)!=0)
{
/* 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);
}
else
{
/* Using MASQUERADE */
snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
"--to-ports %i", fst_port);
}
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_SNAT_RULE_ARGS,
opts->fw_config->fw_command,
snat_chain->table,
snat_chain->to_chain,
fst_proto,
//spadat->use_src_ip,
nat_ip,
//fst_port,
nat_port,
exp_ts,
snat_chain->target,
snat_target
);
//--DSS tmp
fprintf(stderr, "ADD SNAT 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 Source NAT Rule to %s for %s, %s expires at %u",
snat_chain->to_chain, spadat->use_src_ip,
spadat->spa_message_remain, exp_ts
);
snat_chain->active_rules++;
/* Reset the next expected expire time for this chain if it
* is warranted.
*/
if(snat_chain->next_expire < now || exp_ts < snat_chain->next_expire)
snat_chain->next_expire = exp_ts;
}
else
parse_extcmd_error(res, status, err);
}
}
return(res);
@@ -663,7 +740,9 @@ check_firewall_rules(fko_srv_options_t *opts)
*/
for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
{
/* Just in case we somehow lose track and fall out-of-whack.
/* Just in case we somehow lose track and fall out-of-whack,
* we be the hero and reset it to zero.
* (poet but don't know it :-o )
*/
if(ch[i].active_rules < 0)
ch[i].active_rules = 0;
+4 -1
View File
@@ -31,12 +31,15 @@
#define STANDARD_CMD_OUT_BUFSIZE 4096
#define SNAT_TARGET_BUFSIZE 64
/* 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_ADD_SNAT_RULE_ARGS "-t %s -A %s -p %i -d %s --dport %i -m comment --comment _exp_%u -j %s %s"
#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"
@@ -50,7 +53,7 @@
*/
void fw_initialize(fko_srv_options_t *opts);
void fw_cleanup(void);
int process_access_request(fko_srv_options_t *opts, spa_data_t *spdat);
int process_spa_request(fko_srv_options_t *opts, spa_data_t *spdat);
void check_firewall_rules(fko_srv_options_t *opts);
#endif /* FW_UTIL_H */
+41 -29
View File
@@ -123,7 +123,7 @@ ENABLE_IPT_OUTPUT N;
MAX_SNIFF_BYTES 1500;
# Flush all existing rules in the fwknop chains at fwknop start time and/or
# exit time. They default to Y.
# exit time. They default to Y and it is recommended setting.
#
FLUSH_IPT_AT_INIT Y;
FLUSH_IPT_AT_EXIT Y;
@@ -251,50 +251,62 @@ IPT_EXEC_TRIES 1;
#ENABLE_EXT_CMD_PREFIX N;
#EXT_CMD_PREFIX FWKNOP_;
# fwknop uses the IPTables::ChainMgr module to add allow rules to a
# custom iptables chain "FWKNOP_INPUT". This chain is called from
# the INPUT chain, and by default no other iptables chains are used.
# However, additional chains can be added (say, if access needs to
# be allowed through the local system via the FORWARD chain) by
# altering the IPT_FORWARD_ACCESS variable below. For a discussion of
# the format followed by these keywords, read on:
# Specify chain names to which iptables blocking rules will be
# fwknopd adds allow rules to a custom iptables chain "FWKNOP_INPUT".
# This chain is called from the INPUT chain, and by default no other
# iptables chains are used. However, additional chains can be added
# (say, if access needs to be allowed through the local system via the
# FORWARD chain) by altering the IPT_FORWARD_ACCESS variable below.
# For a discussion of the format followed by these keywords, read on:
#
# Specify chain names to which iptables blocking rules will be
# added with the IPT_INPUT_ACCESS and IPT_FORWARD_ACCESS keyword.
# The format for these variables is:
# <Target>,<Direction>,<Table>,<From_chain>,<Jump_rule_position>, \
# <To_chain>,<Rule_position>.
# "Target": Can be any legitimate iptables target, but should usually
# just be "DROP".
# "Direction": Can be "src", "dst", or "both", which correspond to the
# INPUT, OUTPUT, and FORWARD chains.
# "Table": Can be any iptables table, but the default is "filter".
# "From_chain": Is the chain from which packets will be jumped.
# "Jump_rule_position": Defines the position within the From_chain where
# the jump rule is added.
# "To_chain": Is the chain to which packets will be jumped. This is the
# main chain where fwknop rules are added.
# "Rule_position": Defines the position where rule are added within the
# To_chain.
#
IPT_INPUT_ACCESS ACCEPT, src, filter, INPUT, 1, FWKNOP_INPUT, 1;
# <Target>,<Direction>,<Table>,<From_chain>,<Jump_rule_position>,\
# <To_chain>,<Rule_position>.
#
# "Target":
# Can be any legitimate iptables target, but should usually just be "DROP".
#
# "Direction":
# Can be "src", "dst", or "both", which correspond to the INPUT, OUTPUT,
# and FORWARD chains.
#
# "Table":
# Can be any iptables table, but the default is "filter".
#
# "From_chain":
# Is the chain from which packets will be jumped.
#
# "Jump_rule_position":
# Defines the position within the From_chain where the jump rule is added.
#
# "To_chain":
# Is the chain to which packets will be jumped. This is the main chain
# where fwknop rules are added.
#
# "Rule_position":
# Defines the position where rule are added within the To_chain.
#
IPT_INPUT_ACCESS ACCEPT, src, filter, INPUT, 1, FWKNOP_INPUT, 1;
# The IPT_OUTPUT_ACCESS variable is only used if ENABLE_IPT_OUTPUT is enabled
#
IPT_OUTPUT_ACCESS ACCEPT, dst, filter, OUTPUT, 1, FWKNOP_OUTPUT, 1;
IPT_OUTPUT_ACCESS ACCEPT, dst, filter, OUTPUT, 1, FWKNOP_OUTPUT, 1;
# The IPT_FORWARD_ACCESS variable is only used if ENABLE_IPT_FORWARDING is
# enabled.
#
IPT_FORWARD_ACCESS ACCEPT, src, filter, FORWARD, 1, FWKNOP_FORWARD, 1;
IPT_DNAT_ACCESS DNAT, src, nat, PREROUTING, 1, FWKNOP_PREROUTING, 1;
IPT_FORWARD_ACCESS ACCEPT, src, filter, FORWARD, 1, FWKNOP_FORWARD, 1;
IPT_DNAT_ACCESS DNAT, src, nat, PREROUTING, 1, FWKNOP_PREROUTING, 1;
# The IPT_SNAT_ACCESS variable is not used unless both ENABLE_IPT_SNAT and
# ENABLE_IPT_FORWARDING are enabled. Also, the external static IP must be
# set with the SNAT_TRANSLATE_IP variable. The default is to use the
# IPT_MASQUERADE_ACCESS variable.
#
IPT_SNAT_ACCESS SNAT, src, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1;
IPT_MASQUERADE_ACCESS MASQUERADE, src, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1;
IPT_SNAT_ACCESS SNAT, src, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1;
IPT_MASQUERADE_ACCESS MASQUERADE, src, nat, POSTROUTING, 1, FWKNOP_POSTROUTING, 1;
# Directories
#
+11 -3
View File
@@ -240,8 +240,16 @@ incoming_spa(fko_srv_options_t *opts)
*/
res = get_spa_data_fields(ctx, &spadat);
spadat.fw_access_timeout = (acc->fw_access_timeout > 0)
? acc->fw_access_timeout : DEF_FW_ACCESS_TIMEOUT;
/* Figure out what our timeout will be. If it is specified in the SPA
* data, then use that. If not, try the FW_ACCESS_TIMEOUT from the
* access.conf file (if there is one). Otherwise use the default.
*/
if(spadat.client_timeout > 0)
spadat.fw_access_timeout = spadat.client_timeout;
else if(acc->fw_access_timeout > 0)
spadat.fw_access_timeout = acc->fw_access_timeout;
else
spadat.fw_access_timeout = DEF_FW_ACCESS_TIMEOUT;
if(res != FKO_SUCCESS)
{
@@ -364,7 +372,7 @@ incoming_spa(fko_srv_options_t *opts)
/* 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);
res = process_spa_request(opts, &spadat);
#if 0
if(res != FKO_SUCCESS)