* log_msg : New log_set_verbosity(): It sets the default verbosity for the
log module according to the verbose option set by the user through the command
line.
* Remove useless checks of the verbose option when log_msg() is invoked.
922 lines
25 KiB
C
922 lines
25 KiB
C
/*
|
|
*****************************************************************************
|
|
*
|
|
* File: fw_util_ipfw.c
|
|
*
|
|
* Author: Damien S. Stuart
|
|
*
|
|
* Purpose: Fwknop routines for managing ipfw firewall rules.
|
|
*
|
|
* Copyright 2010-2013 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"
|
|
|
|
#if FIREWALL_IPFW
|
|
|
|
#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 unsigned short
|
|
get_next_rule_num(void)
|
|
{
|
|
unsigned short i;
|
|
|
|
for(i=0; i < fwc.max_rules; i++)
|
|
{
|
|
if(fwc.rule_map[i] == RULE_FREE)
|
|
return(fwc.start_rule_num + i);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
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
|
|
ipfw_set_exists(const fko_srv_options_t *opts,
|
|
const char *fw_command, const unsigned short set_num)
|
|
{
|
|
int res = 0;
|
|
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_SET_RULES_ARGS,
|
|
fw_command,
|
|
set_num
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "ipfw_set_exists() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
if(!EXTCMD_IS_SUCCESS(res))
|
|
return(0);
|
|
|
|
if(cmd_out[0] == '\0')
|
|
return(0);
|
|
|
|
return(1);
|
|
}
|
|
|
|
/* Print all firewall rules currently instantiated by the running fwknopd
|
|
* daemon to stdout.
|
|
*/
|
|
int
|
|
fw_dump_rules(const fko_srv_options_t * const opts)
|
|
{
|
|
int res, got_err = 0;
|
|
|
|
if (opts->fw_list_all)
|
|
{
|
|
fprintf(stdout, "Listing all ipfw rules...\n");
|
|
fflush(stdout);
|
|
|
|
zero_cmd_buffers();
|
|
|
|
/* Create the list command for all rules
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_ALL_RULES_ARGS,
|
|
opts->fw_config->fw_command
|
|
);
|
|
|
|
res = system(cmd_buf);
|
|
|
|
log_msg(LOG_INFO, "fw_dump_rules() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
/* 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 fwknopd ipfw rules...\n");
|
|
fflush(stdout);
|
|
|
|
zero_cmd_buffers();
|
|
|
|
/* Create the list command for active rules
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
opts->fw_config->active_set_num
|
|
);
|
|
|
|
printf("\nActive Rules:\n");
|
|
res = system(cmd_buf);
|
|
|
|
log_msg(LOG_INFO, "fw_dump_rules() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
/* 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++;
|
|
}
|
|
|
|
/* Create the list command for expired rules
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
opts->fw_config->expire_set_num
|
|
);
|
|
|
|
printf("\nExpired Rules:\n");
|
|
res = system(cmd_buf);
|
|
|
|
log_msg(LOG_INFO, "fw_dump_rules() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
/* 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);
|
|
}
|
|
|
|
void
|
|
fw_config_init(fko_srv_options_t * const opts)
|
|
{
|
|
int is_err;
|
|
|
|
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], sizeof(fwc.fw_command));
|
|
|
|
fwc.start_rule_num = strtol_wrapper(opts->config[CONF_IPFW_START_RULE_NUM],
|
|
0, RCHK_MAX_IPFW_MAX_RULES, NO_EXIT_UPON_ERR, &is_err);
|
|
if(is_err != FKO_SUCCESS)
|
|
{
|
|
fprintf(stderr, "[*] IPFW_START_RULE_NUM '%s' out of range [%d-%d].\n",
|
|
opts->config[CONF_IPFW_START_RULE_NUM], 0, RCHK_MAX_IPFW_MAX_RULES);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
fwc.max_rules = strtol_wrapper(opts->config[CONF_IPFW_MAX_RULES],
|
|
0, RCHK_MAX_IPFW_MAX_RULES, NO_EXIT_UPON_ERR, &is_err);
|
|
if(is_err != FKO_SUCCESS)
|
|
{
|
|
fprintf(stderr, "[*] IPFW_MAX_RULES_INT '%s' out of range [%d-%d].\n",
|
|
opts->config[CONF_IPFW_MAX_RULES], 0, RCHK_MAX_IPFW_MAX_RULES);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
fwc.active_set_num = strtol_wrapper(opts->config[CONF_IPFW_ACTIVE_SET_NUM],
|
|
0, RCHK_MAX_IPFW_SET_NUM, NO_EXIT_UPON_ERR, &is_err);
|
|
if(is_err != FKO_SUCCESS)
|
|
{
|
|
fprintf(stderr, "[*] IPFW_ACTIVE_SET_NUM '%s' out of range [%d-%d].\n",
|
|
opts->config[CONF_IPFW_ACTIVE_SET_NUM], 0, RCHK_MAX_IPFW_SET_NUM);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
fwc.expire_set_num = strtol_wrapper(opts->config[CONF_IPFW_EXPIRE_SET_NUM],
|
|
0, RCHK_MAX_IPFW_SET_NUM, NO_EXIT_UPON_ERR, &is_err);
|
|
if(is_err != FKO_SUCCESS)
|
|
{
|
|
fprintf(stderr, "[*] IPFW_MAX_EXPIRE_SET_NUM '%s' out of range [%d-%d].\n",
|
|
opts->config[CONF_IPFW_EXPIRE_SET_NUM], 0, RCHK_MAX_IPFW_SET_NUM);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
fwc.purge_interval = strtol_wrapper(opts->config[CONF_IPFW_EXPIRE_PURGE_INTERVAL],
|
|
0, RCHK_MAX_IPFW_PURGE_INTERVAL, NO_EXIT_UPON_ERR, &is_err);
|
|
if(is_err != FKO_SUCCESS)
|
|
{
|
|
fprintf(stderr, "[*] IPFW_EXPIRE_PURGE_INTERVAL '%s' out of range [%d-%d].\n",
|
|
opts->config[CONF_IPFW_EXPIRE_PURGE_INTERVAL], 0,
|
|
RCHK_MAX_IPFW_PURGE_INTERVAL);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Let us find it via our opts struct as well.
|
|
*/
|
|
opts->fw_config = &fwc;
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
fw_initialize(const fko_srv_options_t * const opts)
|
|
{
|
|
int res = 0, is_err;
|
|
unsigned short curr_rule;
|
|
char *ndx;
|
|
|
|
/* For now, we just call fw_cleanup to start with clean slate.
|
|
*/
|
|
if(strncasecmp(opts->config[CONF_FLUSH_IPFW_AT_INIT], "Y", 1) == 0)
|
|
res = fw_cleanup(opts);
|
|
|
|
if(res != 0)
|
|
{
|
|
fprintf(stderr, "Fatal: Errors detected during ipfw rules initialization.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Allocate our rule_map array for tracking active (and expired) rules.
|
|
*/
|
|
fwc.rule_map = calloc(fwc.max_rules, sizeof(char));
|
|
|
|
if(fwc.rule_map == NULL)
|
|
{
|
|
fprintf(stderr, "Fatal: Memory allocation error in fw_initialize.\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Create a check-state rule if necessary.
|
|
*/
|
|
if(strncasecmp(opts->config[CONF_IPFW_ADD_CHECK_STATE], "Y", 1) == 0)
|
|
{
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_ADD_CHECK_STATE_ARGS,
|
|
fwc.fw_command,
|
|
fwc.start_rule_num,
|
|
fwc.active_set_num
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "fw_initialize() CMD: '%s' (res: %d, err: %s)",
|
|
cmd_buf, res, err_buf);
|
|
|
|
if(EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_INFO, "Added check-state rule %u to set %u",
|
|
fwc.start_rule_num,
|
|
fwc.active_set_num
|
|
);
|
|
|
|
fwc.rule_map[0] = RULE_ACTIVE;
|
|
}
|
|
else
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
|
|
if(fwc.expire_set_num > 0
|
|
&& (strncasecmp(opts->config[CONF_FLUSH_IPFW_AT_INIT], "Y", 1) == 0))
|
|
{
|
|
/* Make sure our expire set is disabled.
|
|
*/
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_DISABLE_SET_ARGS,
|
|
fwc.fw_command,
|
|
fwc.expire_set_num
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "fw_initialize() CMD: '%s' (res: %d, err: %s)",
|
|
cmd_buf, res, err_buf);
|
|
|
|
if(EXTCMD_IS_SUCCESS(res))
|
|
log_msg(LOG_INFO, "Set ipfw expire set %u to disabled.",
|
|
fwc.expire_set_num);
|
|
else
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
|
|
/* Now read the expire set in case there are existing
|
|
* rules to track.
|
|
*/
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_EXP_SET_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
fwc.expire_set_num
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "fw_initialize() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
if(!EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
|
|
return;
|
|
}
|
|
|
|
log_msg(LOG_DEBUG, "RULES LIST: %s", cmd_out);
|
|
|
|
/* Find the first "# DISABLED" string (if any).
|
|
*/
|
|
ndx = strstr(cmd_out, "# DISABLED ");
|
|
|
|
/* Assume no disabled rules if we did not see the string.
|
|
*/
|
|
if(ndx == NULL)
|
|
return;
|
|
|
|
/* Otherwise we walk each line to pull the rule number and
|
|
* set the appropriate rule map entries.
|
|
*/
|
|
while(ndx != NULL)
|
|
{
|
|
/* Skip over the DISABLED string to the rule num.
|
|
*/
|
|
ndx += 11;
|
|
|
|
if(isdigit(*ndx))
|
|
{
|
|
curr_rule = strtol_wrapper(ndx, 0, -1, NO_EXIT_UPON_ERR, &is_err);
|
|
|
|
if(is_err == FKO_SUCCESS)
|
|
{
|
|
if(curr_rule >= fwc.start_rule_num
|
|
&& curr_rule < fwc.start_rule_num + fwc.max_rules)
|
|
{
|
|
fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_EXPIRED;
|
|
fwc.total_rules++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
log_msg(LOG_WARNING, "fw_initialize: No rule number found where expected.");
|
|
|
|
/* Find the next "# DISABLED" string (if any).
|
|
*/
|
|
ndx = strstr(ndx, "# DISABLED ");
|
|
}
|
|
}
|
|
|
|
int
|
|
fw_cleanup(const fko_srv_options_t * const opts)
|
|
{
|
|
int res, got_err = 0;
|
|
|
|
if(strncasecmp(opts->config[CONF_FLUSH_IPFW_AT_EXIT], "N", 1) == 0)
|
|
{
|
|
if(fwc.rule_map != NULL)
|
|
free(fwc.rule_map);
|
|
return(0);
|
|
}
|
|
|
|
zero_cmd_buffers();
|
|
|
|
if(fwc.active_set_num > 0
|
|
&& ipfw_set_exists(opts, fwc.fw_command, fwc.active_set_num))
|
|
{
|
|
/* Create the set delete command for active rules
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_DEL_RULE_SET_ARGS,
|
|
fwc.fw_command,
|
|
fwc.active_set_num
|
|
);
|
|
|
|
res = system(cmd_buf);
|
|
|
|
log_msg(LOG_INFO, "fw_cleanup() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
/* 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++;
|
|
}
|
|
}
|
|
|
|
/* --DSS Keep expired rule list so any existing established
|
|
are not lost */
|
|
#if 0
|
|
|
|
if(fwc.expire_set_num > 0)
|
|
{
|
|
/* Create the set delete command for expired rules
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_DEL_RULE_SET_ARGS,
|
|
fwc.fw_command,
|
|
fwc.expire_set_num
|
|
);
|
|
|
|
//printf("CMD: '%s'\n", 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++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Free the rule map.
|
|
*/
|
|
if(fwc.rule_map != NULL)
|
|
free(fwc.rule_map);
|
|
|
|
return(got_err);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Rule Processing - Create an access request...
|
|
*/
|
|
int
|
|
process_spa_request(const fko_srv_options_t * const opts,
|
|
const acc_stanza_t * const acc, spa_data_t * const spadat)
|
|
{
|
|
unsigned short rule_num;
|
|
|
|
acc_port_list_t *port_list = NULL;
|
|
acc_port_list_t *ple;
|
|
|
|
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;
|
|
|
|
/* 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)
|
|
{
|
|
/* Pull the next available rule number.
|
|
*/
|
|
rule_num = get_next_rule_num();
|
|
|
|
/* If rule_num comes back as 0, we aready have the maximum number
|
|
* of active rules allowed so we reject and bail here.
|
|
*/
|
|
if(rule_num == 0)
|
|
{
|
|
log_msg(LOG_WARNING, "Access request rejected: Maximum allowed number of rules has been reached.");
|
|
free_acc_port_list(port_list);
|
|
return(-1);
|
|
}
|
|
|
|
/* 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 " IPFW_ADD_RULE_ARGS,
|
|
fwc.fw_command,
|
|
rule_num,
|
|
fwc.active_set_num,
|
|
ple->proto,
|
|
spadat->use_src_ip,
|
|
ple->port,
|
|
exp_ts
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
|
|
cmd_buf, res, err_buf);
|
|
|
|
if(EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_INFO, "Added Rule %u for %s, %s expires at %u",
|
|
rule_num,
|
|
spadat->use_src_ip,
|
|
spadat->spa_message_remain, exp_ts
|
|
);
|
|
|
|
fwc.rule_map[rule_num - fwc.start_rule_num] = RULE_ACTIVE;
|
|
|
|
fwc.active_rules++;
|
|
fwc.total_rules++;
|
|
|
|
/* Reset the next expected expire time for this chain if it
|
|
* is warranted.
|
|
*/
|
|
if(fwc.next_expire < now || exp_ts < fwc.next_expire)
|
|
fwc.next_expire = exp_ts;
|
|
}
|
|
else
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
|
|
ple = ple->next;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
/* No other SPA request modes are supported yet.
|
|
*/
|
|
if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
|
|
|| spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG)
|
|
{
|
|
log_msg(LOG_WARNING, "Local NAT requests are not currently supported.");
|
|
}
|
|
else if(spadat->message_type == FKO_NAT_ACCESS_MSG
|
|
|| spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG)
|
|
{
|
|
log_msg(LOG_WARNING, "Forwarding/NAT requests are not currently supported.");
|
|
}
|
|
|
|
free_acc_port_list(port_list);
|
|
return(-1);
|
|
}
|
|
|
|
free_acc_port_list(port_list);
|
|
return(res);
|
|
}
|
|
|
|
/* Iterate over the current rule set and purge expired
|
|
* firewall rules.
|
|
*/
|
|
void
|
|
check_firewall_rules(const fko_srv_options_t * const opts)
|
|
{
|
|
char exp_str[12] = {0};
|
|
char rule_num_str[6] = {0};
|
|
char *ndx, *rn_start, *rn_end, *tmp_mark;
|
|
|
|
int i=0, res=0, is_err;
|
|
time_t now, rule_exp, min_exp = 0;
|
|
unsigned short curr_rule;
|
|
|
|
/* Just in case we somehow lose track and fall out-of-whack.
|
|
*/
|
|
if(fwc.active_rules > fwc.max_rules)
|
|
fwc.active_rules = 0;
|
|
|
|
/* If there are no active rules or we have not yet
|
|
* reached our expected next expire time, continue.
|
|
*/
|
|
if(fwc.active_rules == 0)
|
|
return;
|
|
|
|
time(&now);
|
|
|
|
if (fwc.next_expire > now)
|
|
return;
|
|
|
|
zero_cmd_buffers();
|
|
|
|
/* 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 " IPFW_LIST_SET_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
fwc.active_set_num
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
if(!EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
|
|
return;
|
|
}
|
|
|
|
log_msg(LOG_DEBUG, "RULES LIST: %s", cmd_out);
|
|
|
|
/* Find the first _exp_ string (if any).
|
|
*/
|
|
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 (fwc.active_rules > 0)
|
|
fwc.active_rules--;
|
|
|
|
return;
|
|
}
|
|
|
|
/* 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, sizeof(exp_str));
|
|
rule_exp = (time_t)atoll(exp_str);
|
|
|
|
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')
|
|
{
|
|
rn_start++;
|
|
}
|
|
else if(rn_start > cmd_out)
|
|
{
|
|
/* 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.");
|
|
|
|
if (fwc.active_rules > 0)
|
|
fwc.active_rules--;
|
|
|
|
break;
|
|
}
|
|
|
|
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.");
|
|
|
|
if (fwc.active_rules > 0)
|
|
fwc.active_rules--;
|
|
|
|
break;
|
|
}
|
|
|
|
strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);
|
|
|
|
curr_rule = strtol_wrapper(rule_num_str, 0, -1, NO_EXIT_UPON_ERR, &is_err);
|
|
|
|
if(is_err == FKO_SUCCESS)
|
|
{
|
|
zero_cmd_buffers();
|
|
|
|
/* Move the rule to the expired rules set.
|
|
*/
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_MOVE_RULE_ARGS,
|
|
opts->fw_config->fw_command,
|
|
curr_rule,
|
|
fwc.expire_set_num
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
|
|
cmd_buf, res, err_buf);
|
|
|
|
if(EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_INFO, "Moved rule %s with expire time of %u to set %u.",
|
|
rule_num_str, rule_exp, fwc.expire_set_num
|
|
);
|
|
|
|
if (fwc.active_rules > 0)
|
|
fwc.active_rules--;
|
|
|
|
fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_EXPIRED;
|
|
}
|
|
else
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
|
|
}
|
|
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(fwc.active_rules < 1)
|
|
fwc.next_expire = 0;
|
|
else if(min_exp)
|
|
fwc.next_expire = min_exp;
|
|
}
|
|
|
|
/* Iterate over the expired rule set and purge those that no longer have
|
|
* corresponding dynamic rules.
|
|
*/
|
|
void
|
|
ipfw_purge_expired_rules(const fko_srv_options_t *opts)
|
|
{
|
|
char *ndx, *co_end;
|
|
int i, res, is_err;
|
|
unsigned short curr_rule;
|
|
|
|
/* First, we get the current active dynamic rules for the expired rule
|
|
* set. Then we compare it to the expired rules in the rule_map. Any
|
|
* rules in the map that do not have a dynamic rule, can be deleted.
|
|
*/
|
|
zero_cmd_buffers();
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_LIST_SET_DYN_RULES_ARGS,
|
|
opts->fw_config->fw_command,
|
|
fwc.expire_set_num
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "ipfw_purge_expired_rules() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
if(!EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
|
|
return;
|
|
}
|
|
|
|
/* We may not have any dynamic rules at all - someone might not have
|
|
* initiated a connection (for example)
|
|
*/
|
|
if (cmd_out[0] != '\0')
|
|
{
|
|
co_end = cmd_out + strlen(cmd_out);
|
|
|
|
log_msg(LOG_DEBUG, "EXP RULES LIST: %s", cmd_out);
|
|
|
|
/* Find the "## Dynamic rules" string.
|
|
*/
|
|
ndx = strcasestr(cmd_out, "## Dynamic rules");
|
|
|
|
if(ndx == NULL)
|
|
{
|
|
log_msg(LOG_ERR,
|
|
"Unexpected error: did not find 'Dynamic rules' string in list output."
|
|
);
|
|
return;
|
|
}
|
|
|
|
/* Jump to the next newline char.
|
|
*/
|
|
ndx = strchr(ndx, '\n');
|
|
|
|
if(ndx == NULL)
|
|
{
|
|
log_msg(LOG_ERR,
|
|
"Unexpected error: did not find 'Dynamic rules' line terminating newline."
|
|
);
|
|
return;
|
|
}
|
|
|
|
/* Walk the list of dynamic rules (if any).
|
|
*/
|
|
while(ndx != NULL)
|
|
{
|
|
ndx++;
|
|
|
|
while(!isdigit(*ndx) && ndx < co_end)
|
|
ndx++;
|
|
|
|
if(ndx >= co_end)
|
|
break;
|
|
|
|
/* If we are at a digit, assume it is a rule number, extract it,
|
|
* and if it falls in the correct range, mark it (so it is not
|
|
* removed in the next step.
|
|
*/
|
|
if(isdigit(*ndx))
|
|
{
|
|
curr_rule = strtol_wrapper(ndx, 0, -1, NO_EXIT_UPON_ERR, &is_err);
|
|
|
|
if(is_err == FKO_SUCCESS)
|
|
{
|
|
if(curr_rule >= fwc.start_rule_num
|
|
&& curr_rule < fwc.start_rule_num + fwc.max_rules)
|
|
fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_TMP_MARKED;
|
|
}
|
|
}
|
|
|
|
ndx = strchr(ndx, '\n');
|
|
}
|
|
}
|
|
|
|
/* Now, walk the rule map and remove any still marked as expired.
|
|
*/
|
|
for(i=0; i<fwc.max_rules; i++)
|
|
{
|
|
/* If it is TMP_MARKED, set it back to EXPIRED and move on.
|
|
*/
|
|
if(fwc.rule_map[i] == RULE_TMP_MARKED)
|
|
{
|
|
fwc.rule_map[i] = RULE_EXPIRED;
|
|
continue;
|
|
}
|
|
|
|
/* If it is not expired, move on.
|
|
*/
|
|
if(fwc.rule_map[i] != RULE_EXPIRED)
|
|
continue;
|
|
|
|
/* This rule is ready to go away.
|
|
*/
|
|
zero_cmd_buffers();
|
|
|
|
curr_rule = fwc.start_rule_num + i;
|
|
|
|
snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPFW_DEL_RULE_ARGS,
|
|
opts->fw_config->fw_command,
|
|
#ifndef __APPLE__
|
|
fwc.expire_set_num,
|
|
#endif
|
|
curr_rule
|
|
);
|
|
|
|
res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
|
|
|
|
log_msg(LOG_INFO, "ipfw_purge_expired_rules() CMD: '%s' (res: %d)",
|
|
cmd_buf, res);
|
|
|
|
if(!EXTCMD_IS_SUCCESS(res))
|
|
{
|
|
log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
|
|
continue;
|
|
}
|
|
|
|
log_msg(LOG_INFO, "Purged rule %u from set %u", curr_rule, fwc.expire_set_num);
|
|
|
|
fwc.rule_map[curr_rule - fwc.start_rule_num] = RULE_FREE;
|
|
|
|
fwc.total_rules--;
|
|
}
|
|
}
|
|
|
|
#endif /* FIREWALL_IPFW */
|
|
|
|
/***EOF***/
|