Added new command line options --fw-list-all and --fw-flush to allow all firewall rules to be displayed including those not created by fwknopd, and allow all firewall rules created by fwknopd to be deleted. Also switched -D config dump output to stdout.
957 lines
28 KiB
C
957 lines
28 KiB
C
/*
|
|
*****************************************************************************
|
|
*
|
|
* File: fw_util_iptables.c
|
|
*
|
|
* Author: Damien S. Stuart
|
|
*
|
|
* Purpose: Fwknop routines for managing iptables firewall rules.
|
|
*
|
|
* Copyright 2010 Damien Stuart (dstuart@dstuart.org)
|
|
*
|
|
* License (GNU Public License):
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
* USA
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
|
|
#include "fwknopd_common.h"
|
|
|
|
#ifdef FIREWALL_IPTABLES
|
|
|
|
#include "fw_util.h"
|
|
#include "utils.h"
|
|
#include "log_msg.h"
|
|
#include "extcmd.h"
|
|
#include "access.h"
|
|
|
|
static struct fw_config fwc;
|
|
static char cmd_buf[CMD_BUFSIZE];
|
|
static char err_buf[CMD_BUFSIZE];
|
|
static char cmd_out[STANDARD_CMD_OUT_BUFSIZE];
|
|
|
|
static void
|
|
zero_cmd_buffers(void)
|
|
{
|
|
memset(cmd_buf, 0x0, CMD_BUFSIZE);
|
|
memset(err_buf, 0x0, CMD_BUFSIZE);
|
|
memset(cmd_out, 0x0, STANDARD_CMD_OUT_BUFSIZE);
|
|
}
|
|
|
|
static int
|
|
add_jump_rule(int chain_num)
|
|
{
|
|
int res = 0;
|
|
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS,
|
|
fwc.fw_command,
|
|
fwc.chain[chain_num].table,
|
|
fwc.chain[chain_num].from_chain,
|
|
fwc.chain[chain_num].jump_rule_pos,
|
|
fwc.chain[chain_num].to_chain
|
|
);
|
|
|
|
//printf("(%i) CMD: '%s'\n", i, cmd_buf);
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
|
|
if(EXTCMD_IS_SUCCESS(res))
|
|
log_msg(LOG_INFO, "Added jump rule from chain: %s to chain: %s",
|
|
fwc.chain[chain_num].from_chain,
|
|
fwc.chain[chain_num].to_chain);
|
|
else
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
jump_rule_exists(int chain_num)
|
|
{
|
|
int num, pos = 0;
|
|
char cmd_buf[CMD_BUFSIZE] = {0};
|
|
char target[CMD_BUFSIZE] = {0};
|
|
char line_buf[CMD_BUFSIZE] = {0};
|
|
FILE *ipt;
|
|
|
|
sprintf(cmd_buf, "%s " IPT_LIST_RULES_ARGS,
|
|
fwc.fw_command,
|
|
fwc.chain[chain_num].table,
|
|
fwc.chain[chain_num].from_chain
|
|
);
|
|
|
|
ipt = popen(cmd_buf, "r");
|
|
|
|
if(ipt == NULL)
|
|
{
|
|
log_msg(LOG_ERR,
|
|
"Got error %i trying to get rules list.\n", errno);
|
|
return(-1);
|
|
}
|
|
|
|
while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL)
|
|
{
|
|
/* Get past comments and empty lines (note: we only look at the
|
|
* first character).
|
|
*/
|
|
if(IS_EMPTY_LINE(line_buf[0]))
|
|
continue;
|
|
|
|
if(sscanf(line_buf, "%i %s ", &num, target) == 2)
|
|
{
|
|
if(strcmp(target, fwc.chain[chain_num].to_chain) == 0)
|
|
{
|
|
pos = num;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pclose(ipt);
|
|
|
|
return(pos);
|
|
}
|
|
|
|
/* Print all firewall rules currently instantiated by the running fwknopd
|
|
* daemon to stdout.
|
|
*/
|
|
int
|
|
fw_dump_rules(fko_srv_options_t *opts)
|
|
{
|
|
int i;
|
|
int res, got_err = 0;
|
|
|
|
struct fw_chain *ch = opts->fw_config->chain;
|
|
|
|
if (opts->fw_list_all == 1)
|
|
{
|
|
fprintf(stdout, "Listing all iptables rules in applicable tables...\n");
|
|
fflush(stdout);
|
|
|
|
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
|
|
{
|
|
|
|
if(fwc.chain[i].target[0] == '\0')
|
|
continue;
|
|
|
|
zero_cmd_buffers();
|
|
|
|
/* Create the list command
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_ALL_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
ch[i].table
|
|
);
|
|
|
|
//printf("(%i) CMD: '%s'\n", i, cmd_buf);
|
|
res = system(cmd_buf);
|
|
|
|
/* Expect full success on this */
|
|
if(! EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
got_err++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf(stdout, "Listing rules in fwknopd iptables chains...\n");
|
|
fflush(stdout);
|
|
|
|
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
|
|
{
|
|
|
|
if(fwc.chain[i].target[0] == '\0')
|
|
continue;
|
|
|
|
zero_cmd_buffers();
|
|
|
|
/* Create the list command
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
ch[i].table,
|
|
ch[i].to_chain
|
|
);
|
|
|
|
//printf("(%i) CMD: '%s'\n", i, cmd_buf);
|
|
res = system(cmd_buf);
|
|
|
|
/* Expect full success on this */
|
|
if(! EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
got_err++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(got_err);
|
|
}
|
|
|
|
/* Quietly flush and delete all fwknop custom chains.
|
|
*/
|
|
static void
|
|
delete_all_chains(void)
|
|
{
|
|
int i, res;
|
|
int jump_rule_num;
|
|
|
|
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
|
|
{
|
|
if(fwc.chain[i].target[0] == '\0')
|
|
continue;
|
|
|
|
/* First look for a jump rule to this chain and remove it if it
|
|
* is there.
|
|
*/
|
|
if((jump_rule_num = jump_rule_exists(i)) > 0)
|
|
{
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
|
|
fwc.fw_command,
|
|
fwc.chain[i].table,
|
|
fwc.chain[i].from_chain,
|
|
jump_rule_num
|
|
);
|
|
|
|
//printf("CMD: '%s'\n", cmd_buf);
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
/* Expect full success on this */
|
|
if(! EXTCMD_IS_SUCCESS(res))
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
|
|
zero_cmd_buffers();
|
|
|
|
/* Now flush and remove the chain.
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1,
|
|
"(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1",
|
|
fwc.fw_command,
|
|
fwc.chain[i].table,
|
|
fwc.chain[i].to_chain,
|
|
fwc.fw_command,
|
|
fwc.chain[i].table,
|
|
fwc.chain[i].to_chain
|
|
);
|
|
|
|
//printf("CMD: '%s'\n", cmd_buf);
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
/* Expect full success on this */
|
|
if(! EXTCMD_IS_SUCCESS(res))
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
}
|
|
|
|
/* Create the fwknop custom chains (at least those that are configured).
|
|
*/
|
|
static int
|
|
create_fw_chains(void)
|
|
{
|
|
int i;
|
|
int res, got_err = 0;
|
|
|
|
for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
|
|
{
|
|
if(fwc.chain[i].target[0] == '\0')
|
|
continue;
|
|
|
|
zero_cmd_buffers();
|
|
|
|
/* Create the custom chain.
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
|
|
fwc.fw_command,
|
|
fwc.chain[i].table,
|
|
fwc.chain[i].to_chain
|
|
);
|
|
|
|
//printf("(%i) CMD: '%s'\n", i, cmd_buf);
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
|
|
/* Expect full success on this */
|
|
if(! EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
got_err++;
|
|
}
|
|
|
|
/* Then create the jump rule to that chain.
|
|
*/
|
|
res = add_jump_rule(i);
|
|
|
|
/* Expect full success on this */
|
|
if(! EXTCMD_IS_SUCCESS(res))
|
|
got_err++;
|
|
}
|
|
|
|
return(got_err);
|
|
}
|
|
|
|
|
|
static void
|
|
set_fw_chain_conf(int type, char *conf_str)
|
|
{
|
|
int i, j;
|
|
char tbuf[1024] = {0};
|
|
char *ndx = conf_str;
|
|
|
|
char *chain_fields[FW_NUM_CHAIN_FIELDS];
|
|
|
|
struct fw_chain *chain = &(fwc.chain[type]);
|
|
|
|
chain->type = type;
|
|
|
|
if(ndx != NULL)
|
|
chain_fields[0] = tbuf;
|
|
|
|
i = 0;
|
|
j = 1;
|
|
while(*ndx != '\0')
|
|
{
|
|
if(*ndx != ' ')
|
|
{
|
|
if(*ndx == ',')
|
|
{
|
|
tbuf[i] = '\0';
|
|
chain_fields[j++] = &(tbuf[++i]);
|
|
}
|
|
else
|
|
tbuf[i++] = *ndx;
|
|
}
|
|
ndx++;
|
|
}
|
|
|
|
/* Sanity check - j should be the number of chain fields
|
|
* (excluding the type).
|
|
*/
|
|
if(j != FW_NUM_CHAIN_FIELDS)
|
|
{
|
|
fprintf(stderr, "[*] Custom Chain config parse error.\n"
|
|
"Wrong number of fields for chain type %i\n"
|
|
"Line: %s\n", type, conf_str);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Pull and set Target */
|
|
strlcpy(chain->target, chain_fields[0], MAX_TARGET_NAME_LEN);
|
|
|
|
/* Pull and set Table */
|
|
strlcpy(chain->table, chain_fields[1], MAX_TABLE_NAME_LEN);
|
|
|
|
/* Pull and set From_chain */
|
|
strlcpy(chain->from_chain, chain_fields[2], MAX_CHAIN_NAME_LEN);
|
|
|
|
/* Pull and set Jump_rule_position */
|
|
chain->jump_rule_pos = atoi(chain_fields[3]);
|
|
|
|
/* Pull and set To_chain */
|
|
strlcpy(chain->to_chain, chain_fields[4], MAX_CHAIN_NAME_LEN);
|
|
|
|
/* Pull and set Jump_rule_position */
|
|
chain->rule_pos = atoi(chain_fields[5]);
|
|
|
|
}
|
|
|
|
void
|
|
fw_config_init(fko_srv_options_t *opts)
|
|
{
|
|
|
|
memset(&fwc, 0x0, sizeof(struct fw_config));
|
|
|
|
/* Set our firewall exe command path (iptables in most cases).
|
|
*/
|
|
strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], MAX_PATH_LEN);
|
|
|
|
/* Pull the fwknop chain config info and setup our internal
|
|
* config struct. The IPT_INPUT is the only one that is
|
|
* required. The rest are optional.
|
|
*/
|
|
set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]);
|
|
|
|
/* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y
|
|
*/
|
|
if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0)
|
|
set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]);
|
|
|
|
/* The remaining access chains require ENABLE_IPT_FORWARDING = Y
|
|
*/
|
|
if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0)
|
|
{
|
|
|
|
set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]);
|
|
set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]);
|
|
|
|
/* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y
|
|
*/
|
|
if(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_SNAT_TRANSLATE_IP] != NULL
|
|
&& strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
|
|
set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]);
|
|
else
|
|
set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]);
|
|
}
|
|
}
|
|
|
|
/* Let us find it via our opts struct as well.
|
|
*/
|
|
opts->fw_config = &fwc;
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
fw_initialize(fko_srv_options_t *opts)
|
|
{
|
|
int res;
|
|
|
|
/* Flush the chains (just in case) so we can start fresh.
|
|
*/
|
|
delete_all_chains();
|
|
|
|
/* Now create any configured chains.
|
|
*/
|
|
res = create_fw_chains();
|
|
|
|
if(res != 0)
|
|
{
|
|
fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
int
|
|
fw_cleanup(void)
|
|
{
|
|
delete_all_chains();
|
|
return(0);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Rule Processing - Create an access request...
|
|
*/
|
|
int
|
|
process_spa_request(fko_srv_options_t *opts, spa_data_t *spadat)
|
|
{
|
|
char nat_ip[16] = {0};
|
|
char snat_target[SNAT_TARGET_BUFSIZE] = {0};
|
|
char *ndx;
|
|
|
|
unsigned int nat_port = 0;
|
|
|
|
acc_port_list_t *port_list = NULL;
|
|
acc_port_list_t *ple;
|
|
|
|
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 *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;
|
|
time_t now;
|
|
unsigned int exp_ts;
|
|
|
|
/* Parse and expand our access message.
|
|
*/
|
|
expand_acc_port_list(&port_list, spadat->spa_message_remain);
|
|
|
|
/* Start at the top of the proto-port list...
|
|
*/
|
|
ple = port_list;
|
|
|
|
/* Remember the first proto/port combo in case we need them
|
|
* for NAT access requests.
|
|
*/
|
|
fst_proto = ple->proto;
|
|
fst_port = ple->port;
|
|
|
|
/* 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)
|
|
{
|
|
|
|
/* Check to make sure that the jump rules exist for each
|
|
* required chain
|
|
*/
|
|
if(jump_rule_exists(IPT_INPUT_ACCESS) == 0)
|
|
add_jump_rule(IPT_INPUT_ACCESS);
|
|
|
|
if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
|
|
if(jump_rule_exists(IPT_OUTPUT_ACCESS) == 0)
|
|
add_jump_rule(IPT_OUTPUT_ACCESS);
|
|
|
|
/* Create an access command for each proto/port for the source ip.
|
|
*/
|
|
while(ple != NULL)
|
|
{
|
|
zero_cmd_buffers();
|
|
|
|
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, err_buf, CMD_BUFSIZE, 0);
|
|
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
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
|
|
/* 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))
|
|
{
|
|
zero_cmd_buffers();
|
|
|
|
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, err_buf, CMD_BUFSIZE, 0);
|
|
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
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
|
|
}
|
|
|
|
ple = ple->next;
|
|
}
|
|
|
|
/* Done with the port list for access rules.
|
|
*/
|
|
free_acc_port_list(port_list);
|
|
|
|
}
|
|
/* 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 )
|
|
{
|
|
/* 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))
|
|
{
|
|
|
|
/* Make sure the required jump rule exists
|
|
*/
|
|
if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
|
|
add_jump_rule(IPT_FORWARD_ACCESS);
|
|
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_FWD_RULE_ARGS,
|
|
opts->fw_config->fw_command,
|
|
fwd_chain->table,
|
|
fwd_chain->to_chain,
|
|
fst_proto,
|
|
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, err_buf, CMD_BUFSIZE, 0);
|
|
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
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
|
|
if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
|
|
{
|
|
|
|
/* Make sure the required jump rule exists
|
|
*/
|
|
if (jump_rule_exists(IPT_DNAT_ACCESS) == 0)
|
|
add_jump_rule(IPT_DNAT_ACCESS);
|
|
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_DNAT_RULE_ARGS,
|
|
opts->fw_config->fw_command,
|
|
dnat_chain->table,
|
|
dnat_chain->to_chain,
|
|
fst_proto,
|
|
spadat->use_src_ip,
|
|
fst_port,
|
|
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, err_buf, CMD_BUFSIZE, 0);
|
|
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
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
zero_cmd_buffers();
|
|
|
|
/* Setup some parameter depending on whether we are using SNAT
|
|
* or MASQUERADE.
|
|
*/
|
|
if(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,
|
|
nat_ip,
|
|
nat_port,
|
|
exp_ts,
|
|
snat_chain->target,
|
|
snat_target
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
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
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
}
|
|
|
|
return(res);
|
|
}
|
|
|
|
/* Iterate over the configure firewall access chains and purge expired
|
|
* firewall rules.
|
|
*/
|
|
void
|
|
check_firewall_rules(fko_srv_options_t *opts)
|
|
{
|
|
char exp_str[12];
|
|
char rule_num_str[6];
|
|
char *ndx, *rn_start, *rn_end, *tmp_mark;
|
|
|
|
int i, res, rn_offset;
|
|
time_t now, rule_exp, min_exp = 0;
|
|
|
|
struct fw_chain *ch = opts->fw_config->chain;
|
|
|
|
time(&now);
|
|
|
|
/* Iterate over each chain and look for active rules to delete.
|
|
*/
|
|
for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
|
|
{
|
|
/* If there are no active rules or we have not yet
|
|
* reached our expected next expire time, continue.
|
|
*/
|
|
if(ch[i].active_rules == 0 || ch[i].next_expire > now)
|
|
continue;
|
|
|
|
zero_cmd_buffers();
|
|
|
|
rn_offset = 0;
|
|
|
|
/* There should be a rule to delete. Get the current list of
|
|
* rules for this chain and delete the ones that are expired.
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
ch[i].table,
|
|
ch[i].to_chain
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
|
|
|
|
if(!EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
|
|
continue;
|
|
}
|
|
|
|
if(opts->verbose > 2)
|
|
log_msg(LOG_INFO, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out);
|
|
|
|
ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);
|
|
if(ndx == NULL)
|
|
{
|
|
/* we did not find an expected rule.
|
|
*/
|
|
log_msg(LOG_ERR,
|
|
"Did not find expire comment in rules list %i.\n", i);
|
|
|
|
if (ch[i].active_rules > 0)
|
|
ch[i].active_rules--;
|
|
|
|
continue;
|
|
}
|
|
|
|
/* walk the list and process rules as needed.
|
|
*/
|
|
while (ndx != NULL) {
|
|
/* Jump forward and extract the timestamp
|
|
*/
|
|
ndx += strlen(EXPIRE_COMMENT_PREFIX);
|
|
|
|
/* remember this spot for when we look for the next
|
|
* rule.
|
|
*/
|
|
tmp_mark = ndx;
|
|
|
|
strlcpy(exp_str, ndx, 11);
|
|
rule_exp = (time_t)atoll(exp_str);
|
|
|
|
//fprintf(stderr, "RULE_EXP=%u, NOW=%u\n", rule_exp, now);
|
|
if(rule_exp <= now)
|
|
{
|
|
/* Backtrack and get the rule number and delete it.
|
|
*/
|
|
rn_start = ndx;
|
|
while(--rn_start > cmd_out)
|
|
{
|
|
if(*rn_start == '\n')
|
|
break;
|
|
}
|
|
|
|
if(*rn_start != '\n')
|
|
{
|
|
/* This should not happen. But if it does, complain,
|
|
* decrement the active rule value, and go on.
|
|
*/
|
|
log_msg(LOG_ERR,
|
|
"Rule parse error while finding rule line start in chain %i", i);
|
|
|
|
if (ch[i].active_rules > 0)
|
|
ch[i].active_rules--;
|
|
|
|
break;
|
|
}
|
|
rn_start++;
|
|
|
|
rn_end = strchr(rn_start, ' ');
|
|
if(rn_end == NULL)
|
|
{
|
|
/* This should not happen. But if it does, complain,
|
|
* decrement the active rule value, and go on.
|
|
*/
|
|
log_msg(LOG_ERR,
|
|
"Rule parse error while finding rule number in chain %i", i);
|
|
|
|
if (ch[i].active_rules > 0)
|
|
ch[i].active_rules--;
|
|
|
|
break;
|
|
}
|
|
|
|
strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);
|
|
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
|
|
opts->fw_config->fw_command,
|
|
ch[i].table,
|
|
ch[i].to_chain,
|
|
atoi(rule_num_str) - rn_offset
|
|
);
|
|
|
|
|
|
//fprintf(stderr, "DELETE RULE CMD: %s\n", cmd_buf);
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
if(EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u.",
|
|
rule_num_str, ch[i].to_chain, rule_exp
|
|
);
|
|
|
|
rn_offset++;
|
|
|
|
if (ch[i].active_rules > 0)
|
|
ch[i].active_rules--;
|
|
}
|
|
else
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
|
|
}
|
|
else
|
|
{
|
|
/* Track the minimum future rule expire time.
|
|
*/
|
|
if(rule_exp > now)
|
|
min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
|
|
}
|
|
|
|
/* Push our tracking index forward beyond (just processed) _exp_
|
|
* string so we can continue to the next rule in the list.
|
|
*/
|
|
ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
|
|
}
|
|
|
|
/* Set the next pending expire time accordingly. 0 if there are no
|
|
* more rules, or whatever the next expected (min_exp) time will be.
|
|
*/
|
|
if(ch[i].active_rules < 1)
|
|
ch[i].next_expire = 0;
|
|
else if(min_exp)
|
|
ch[i].next_expire = min_exp;
|
|
}
|
|
}
|
|
|
|
#endif /* FIREWALL_IPTABLES */
|
|
|
|
/***EOF***/
|