/* Create the fwknop custom chains (at least those that are configured).
*/
static int
create_fw_chains(const fko_srv_options_t * const opts)
{
    int     i, got_err = 0;

    for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
    {
        if(fwc.chain[i].target[0] == '\0')
            continue;

        if(chain_exists(opts, i) == 0)
        {

            /* Create the chain
            */
            if(! EXTCMD_IS_SUCCESS(create_chain(opts, i)))
                got_err++;

            /* Then create the jump rule to that chain if it
             * doesn't already exist (which is possible)
            */
            if(jump_rule_exists(opts, i) == 0)
                if(! EXTCMD_IS_SUCCESS(add_jump_rule(opts, i)))
                    got_err++;
        }
    }

    return(got_err);
}
Beispiel #2
0
int
fw_cleanup(void)
{
    int     res, got_err = 0;

    zero_cmd_buffers();

    if(fwc.active_set_num > 0
        && ipfw_set_exists(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
        );

        //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++;
        }
    }

/* --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);
}
Beispiel #3
0
/* Check to see if the fwknop anchor is linked into the main policy.  If not,
 * any rules added/deleted by fwknopd will have no effect on real traffic.
*/
static int
anchor_active(const fko_srv_options_t *opts)
{
    int    res = 0;
    char   anchor_search_str[MAX_PF_ANCHOR_SEARCH_LEN] = {0};

    /* Build our anchor search string
    */
    snprintf(anchor_search_str, MAX_PF_ANCHOR_SEARCH_LEN-1, "%s\n",
        opts->fw_config->anchor);

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_ANCHOR_CHECK_ARGS,
        opts->fw_config->fw_command
    );

    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);
        return 0;
    }

    /* Check to see if the anchor exists and is linked into the main policy
    */

    if(strstr(cmd_out, anchor_search_str) == NULL)
        return 0;

    return 1;
}
Beispiel #4
0
static int
add_jump_rule(const fko_srv_options_t *opts, const 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
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

    if (opts->verbose)
        log_msg(LOG_INFO, "add_jump_rule() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_buf);

    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;
}
Beispiel #5
0
static int
chain_exists(const fko_srv_options_t * const opts, const int chain_num)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHAIN_EXISTS_ARGS,
        fwc.fw_command,
        fwc.chain[chain_num].table,
        fwc.chain[chain_num].to_chain
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "chain_exists() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res))
        log_msg(LOG_DEBUG, "'%s' table '%s' chain exists",
            fwc.chain[chain_num].table,
            fwc.chain[chain_num].to_chain);
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return res;
}
Beispiel #6
0
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);

    if (opts->verbose)
        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);
}
Beispiel #7
0
/* Print all firewall rules currently instantiated by the running fwknopd
 * daemon to stdout.
*/
int
fw_dump_rules(const fko_srv_options_t *opts)
{
    int     res, got_err = 0;

    printf("Listing fwknopd pf rules...\n");

    zero_cmd_buffers();

    /* Create the list command for active rules
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_LIST_ANCHOR_RULES_ARGS,
        opts->fw_config->fw_command,
        opts->fw_config->anchor
    );

    printf("\nActive Rules in PF anchor '%s':\n", opts->fw_config->anchor);
    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);
}
Beispiel #8
0
static int
add_jump_rule(const fko_srv_options_t * const opts, const int chain_num)
{
    int res = 0, rv = 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
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);

    log_msg(LOG_DEBUG, "add_jump_rule() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    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);
        rv = 1;
    }
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return rv;
}
Beispiel #9
0
static int
rule_exists_chk_support(const fko_srv_options_t * const opts,
        const char * const chain, const char * const rule)
{
    int     rule_exists = 0;
    int     res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_CHK_RULE_ARGS,
            opts->fw_config->fw_command, chain, rule);

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "rule_exists_chk_support() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf))
    {
        log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s does not exist",
                rule, chain);
    }
    else
    {
        rule_exists = 1;
        log_msg(LOG_DEBUG, "rule_exists_chk_support() Rule : '%s' in %s already exists",
                rule, chain);
    }

    return(rule_exists);
}
Beispiel #10
0
static int
create_rule(const fko_srv_options_t * const opts,
        const char * const fw_chain, const char * const fw_rule)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s -A %s %s",
            opts->fw_config->fw_command, fw_chain, fw_rule);

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "create_rule() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res))
    {
        log_msg(LOG_DEBUG, "create_rule() Rule: '%s' added to %s",
                fw_rule, fw_chain);
        res = 1;
    }
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return res;
}
Beispiel #11
0
static int
create_chain(const fko_srv_options_t * const opts, const int chain_num)
{
    int res = 0, rv = 0;

    zero_cmd_buffers();

    /* Create the custom chain.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
        fwc.fw_command,
        fwc.chain[chain_num].table,
        fwc.chain[chain_num].to_chain
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "create_chain() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    /* Expect full success on this */
    if(EXTCMD_IS_SUCCESS(res))
        rv = 1;
    else
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);

    return rv;
}
Beispiel #12
0
/* Create the fwknop custom chains (at least those that are configured).
*/
static int
create_fw_chains(const fko_srv_options_t *opts)
{
    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
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

        if (opts->verbose)
            log_msg(LOG_INFO, "create_fw_chains() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_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++;
        }

        /* Then create the jump rule to that chain.
        */
        res = add_jump_rule(opts, i);

        /* Expect full success on this */
        if(! EXTCMD_IS_SUCCESS(res))
            got_err++;
    }

    return(got_err);
}
Beispiel #13
0
/* Print all firewall rules currently instantiated by the running fwknopd
 * daemon to stdout.
*/
int
fw_dump_rules(fko_srv_options_t *opts)
{
    int     res, got_err = 0;

    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("(%i) CMD: '%s'\n", i, cmd_buf);
    printf("\nActive Rules:\n");
    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++;
    }

    /* 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("(%i) CMD: '%s'\n", i, cmd_buf);
    printf("\nExpired Rules:\n");
    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);
}
Beispiel #14
0
static void
delete_all_anchor_rules(const fko_srv_options_t *opts)
{
    int res = 0;

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_DEL_ALL_ANCHOR_RULES,
        fwc.fw_command,
        fwc.anchor
    );

    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);

    return;
}
Beispiel #15
0
static int
ipfw_set_exists(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);

    if(!EXTCMD_IS_SUCCESS(res))
        return(0);

    if(cmd_out[0] == '\0')
        return(0);

    return(1);
}
Beispiel #16
0
/* Iterate over the current rule set and purge expired
 * firewall rules.
*/
void
check_firewall_rules(const fko_srv_options_t *opts)
{
    char            exp_str[12];
    char            rule_num_str[6];
    char           *ndx, *rn_start, *rn_end, *tmp_mark;

    int             i=0, res=0;
    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);

    if (opts->verbose)
        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;
    }

    if(opts->verbose > 1)
        log_msg(LOG_INFO, "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, 11);
        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 = atoi(rule_num_str);

            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);

            if (opts->verbose)
                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
        {
            /* 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;
}
Beispiel #17
0
int
fw_cleanup(const fko_srv_options_t *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);

        if (opts->verbose)
            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);
}
Beispiel #18
0
/* Rule Processing - Create an access request...
*/
int
process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
{
    unsigned short   rule_num;

    acc_port_list_t *port_list = NULL;
    acc_port_list_t *ple;

    unsigned int    fst_proto;
    unsigned int    fst_port;

    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)
    {
        /* 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.");
            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);

            if (opts->verbose)
                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.");
        }

        return(-1);
    }

    return(res);
}
Beispiel #19
0
void
fw_initialize(const fko_srv_options_t *opts)
{
    int             res = 0;
    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);

        if (opts->verbose)
            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);

        if (opts->verbose)
            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);

    if (opts->verbose)
        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;
    }

    if(opts->verbose > 1)
        log_msg(LOG_INFO, "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 = atoi(ndx);

            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 ");
    }
}
Beispiel #20
0
/* Iterate over the configure firewall access chains 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, res, rn_offset, rule_num, is_err;
    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,
                WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
        chop_newline(cmd_out);

        log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, cmd_out: %s)",
            cmd_buf, res, cmd_out);

        if(!EXTCMD_IS_SUCCESS(res))
        {
            log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
            continue;
        }

        log_msg(LOG_DEBUG, "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", 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, 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')
                {
                    /* 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);

                rule_num = strtol_wrapper(rule_num_str, rn_offset, RCHK_MAX_IPT_RULE_NUM,
                        NO_EXIT_UPON_ERR, &is_err);
                if(is_err != FKO_SUCCESS)
                {
                    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;
                }

                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,
                    rule_num - rn_offset
                );

                res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
                        WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
                chop_newline(err_buf);

                log_msg(LOG_DEBUG, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_buf);

                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;
    }
}
Beispiel #21
0
static void
ipt_chk_support(const fko_srv_options_t * const opts)
{
    int               res = 1;
    struct fw_chain  *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);

    zero_cmd_buffers();

    /* Add a harmless rule to the iptables INPUT chain and see if iptables
     * supports '-C' to check for it.  Set "have_ipt_chk_support" accordingly,
     * delete the rule, and return.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_CHK_RULE_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        1,   /* first rule */
        in_chain->target
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "ipt_chk_support() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    zero_cmd_buffers();

    /* Now see if '-C' works - any output indicates failure
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_VERIFY_CHK_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        in_chain->target
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "ipt_chk_support() CMD: '%s' (res: %d, err: %s)",
        cmd_buf, res, err_buf);

    if(EXTCMD_IS_SUCCESS(res) && strlen(err_buf))
    {
        log_msg(LOG_DEBUG, "ipt_chk_support() -C not supported");
        have_ipt_chk_support = 0;
    }
    else
    {
        log_msg(LOG_DEBUG, "ipt_chk_support() -C supported");
        have_ipt_chk_support = 1;
    }

    /* Delete the tmp rule
    */
    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        1
    );
    run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);

    return;
}
Beispiel #22
0
static int
comment_match_exists(const fko_srv_options_t * const opts)
{
    int               res = 1;
    char             *ndx = NULL;
    struct fw_chain  *in_chain  = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);

    zero_cmd_buffers();

    /* Add a harmless rule to the iptables INPUT chain that uses the comment
     * match and make sure it exists.  If not, return zero.  Otherwise, delete
     * the rule and return true.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_COMMENT_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain,
        1,   /* first rule */
        in_chain->target
    );

    res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(err_buf);

    log_msg(LOG_DEBUG, "comment_match_exists() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_buf);

    zero_cmd_buffers();

    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
        opts->fw_config->fw_command,
        in_chain->table,
        in_chain->from_chain
    );

    res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE,
            WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    chop_newline(cmd_out);

    if(!EXTCMD_IS_SUCCESS(res))
        log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);

    ndx = strstr(cmd_out, TMP_COMMENT);
    if(ndx == NULL)
        res = 0;  /* did not find the tmp comment */
    else
        res = 1;

    if(res == 1)
    {
        /* Delete the tmp comment rule
        */
        zero_cmd_buffers();

        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
            opts->fw_config->fw_command,
            in_chain->table,
            in_chain->from_chain,
            1
        );
        run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
                WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
    }

    return res;
}
Beispiel #23
0
/* 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;

    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);

    if (opts->verbose)
        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);

        if(opts->verbose > 1)
            log_msg(LOG_INFO, "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 = atoi(ndx);

                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);

        if (opts->verbose)
            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--;
    }
}
Beispiel #24
0
/* Print all firewall rules currently instantiated by the running fwknopd
 * daemon to stdout.
*/
int
fw_dump_rules(const fko_srv_options_t *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);

        if (opts->verbose)
            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);

        if (opts->verbose)
            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);

        if (opts->verbose)
            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);
}
Beispiel #25
0
/* Quietly flush and delete all fwknop custom chains.
*/
static void
delete_all_chains(const fko_srv_options_t *opts)
{
    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
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
                    cmd_buf, res, err_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);
        }

        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
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

        if (opts->verbose)
            log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_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);
    }
}
Beispiel #26
0
/* Iterate over the configure firewall access chains and purge expired
 * firewall rules.
*/
void
check_firewall_rules(const fko_srv_options_t *opts)
{
    char            exp_str[12];
    char            anchor_rules_copy[STANDARD_CMD_OUT_BUFSIZE];
    char            write_cmd[CMD_BUFSIZE];
    char           *ndx, *tmp_mark, *tmp_ndx, *newline_tmp_ndx;

    time_t          now, rule_exp, min_exp=0;
    int             i=0, res=0, anchor_ndx=0, is_delete=0;

    FILE            *pfctl_fd = NULL;

    /* If we have not yet reached our expected next expire
       time, continue.
    */
    if(fwc.next_expire == 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 and delete the ones that are expired.
    */
    snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " PF_LIST_ANCHOR_RULES_ARGS,
        opts->fw_config->fw_command,
        opts->fw_config->anchor
    );

    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);
        return;
    }

    /* 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);

        return;
    }

    memset(anchor_rules_copy, 0x0, STANDARD_CMD_OUT_BUFSIZE);

    /* 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);

        if(rule_exp <= now)
        {
            /* We are going to delete this rule, and because we rebuild the
             * PF anchor to include all rules that haven't expired, to delete
             * this rule we just skip to the next one.
            */
            log_msg(LOG_INFO, "Deleting rule with expire time of %u.", rule_exp);

            if (fwc.active_rules > 0)
                fwc.active_rules--;

            is_delete = 1;
        }
        else
        {
            /* The rule has not expired, so copy it into the anchor string that
             * lists current rules and will be used to feed
             * 'pfctl -a <anchor> -f -'.
            */

            /* back up to the previous newline or the beginning of the rules
             * output string.
            */
            tmp_ndx = ndx;
            while(--tmp_ndx > cmd_out)
            {
                if(*tmp_ndx == '\n')
                    break;
            }

            if(*tmp_ndx == '\n')
            {
                tmp_ndx++;
            }

            /* may sure the rule begins with the string "pass", and make sure
             * it ends with a newline.  Bail if either test fails.
            */
            if (strlen(tmp_ndx) <= strlen("pass")
                || strncmp(tmp_ndx, "pass", strlen("pass")) != 0)
            {
                break;
            }

            newline_tmp_ndx = tmp_ndx;
            while (*newline_tmp_ndx != '\n' && *newline_tmp_ndx != '\0')
            {
                newline_tmp_ndx++;
            }

            if (*newline_tmp_ndx != '\n')
                break;

            /* copy the whole rule to the next newline (includes the expiration
               time).
            */
            while (*tmp_ndx != '\n' && *tmp_ndx != '\0'
                && anchor_ndx < STANDARD_CMD_OUT_BUFSIZE)
            {
                anchor_rules_copy[anchor_ndx] = *tmp_ndx;
                tmp_ndx++;
                anchor_ndx++;
            }
            anchor_rules_copy[anchor_ndx] = '\n';
            anchor_ndx++;

            /* 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);

    }

    if (is_delete)
    {
        /* We re-instantiate the anchor rules with the new rules string that
         * has the rule(s) deleted.  If there isn't at least one "pass" rule,
         * then we just flush the anchor.
        */

        if (strlen(anchor_rules_copy) > strlen("pass")
            && strncmp(anchor_rules_copy, "pass", strlen("pass")) == 0)
        {
            memset(write_cmd, 0x0, CMD_BUFSIZE);

            snprintf(write_cmd, CMD_BUFSIZE-1, "%s " PF_WRITE_ANCHOR_RULES_ARGS,
                opts->fw_config->fw_command,
                opts->fw_config->anchor
            );

            if ((pfctl_fd = popen(write_cmd, "w")) == NULL)
            {
                log_msg(LOG_WARNING, "Could not execute command: %s",
                    write_cmd);
                return;
            }

            if (fwrite(anchor_rules_copy, strlen(anchor_rules_copy), 1, pfctl_fd) != 1)
            {
                log_msg(LOG_WARNING, "Could not write rules to pf anchor");
            }
            pclose(pfctl_fd);
        }
        else
        {
            delete_all_anchor_rules(opts);
        }

    }

    /* 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;

    return;
}
Beispiel #27
0
/* Quietly flush and delete all fwknop custom chains.
*/
static void
delete_all_chains(const fko_srv_options_t * const opts)
{
    int     i, res, cmd_ctr = 0;

    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.
        */
        cmd_ctr = 0;
        while(cmd_ctr < CMD_LOOP_TRIES && (jump_rule_exists(opts, i) == 1))
        {
            zero_cmd_buffers();

            snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_JUMP_RULE_ARGS,
                fwc.fw_command,
                fwc.chain[i].table,
                fwc.chain[i].from_chain,
                fwc.chain[i].to_chain
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE,
                    WANT_STDERR, NO_TIMEOUT, &pid_status, opts);
            chop_newline(err_buf);

            log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
                cmd_buf, res, err_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);

            cmd_ctr++;
        }

        zero_cmd_buffers();

        /* Now flush and remove the chain.
        */
        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_FLUSH_CHAIN_ARGS,
            fwc.fw_command,
            fwc.chain[i].table,
            fwc.chain[i].to_chain
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
        chop_newline(err_buf);

        log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_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);

        zero_cmd_buffers();

        snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_CHAIN_ARGS,
            fwc.fw_command,
            fwc.chain[i].table,
            fwc.chain[i].to_chain
        );

        res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, WANT_STDERR,
                NO_TIMEOUT, &pid_status, opts);
        chop_newline(err_buf);

        log_msg(LOG_DEBUG, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
            cmd_buf, res, err_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);
    }
    return;
}
Beispiel #28
0
/* 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     i, 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
            );

            res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR,
                        NO_TIMEOUT, &pid_status, opts);

            log_msg(LOG_DEBUG, "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 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
            );

            fprintf(stdout, "\n");
            fflush(stdout);

            res = run_extcmd(cmd_buf, NULL, 0, NO_STDERR,
                        NO_TIMEOUT, &pid_status, opts);

            log_msg(LOG_DEBUG, "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);
}
Beispiel #29
0
/* Rule Processing - Create an access request...
*/
int
process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
{
    char             nat_ip[MAX_IPV4_STR_LEN] = {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.
    */
    if(expand_acc_port_list(&port_list, spadat->spa_message_remain) != 1)
        return res;

    /* 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) && !acc->force_nat)
    {

        /* Check to make sure that the jump rules exist for each
         * required chain
        */
        if(jump_rule_exists(IPT_INPUT_ACCESS) == 0)
            add_jump_rule(opts, 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(opts, 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
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                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 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
                );

                res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

                if (opts->verbose)
                    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 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;
        }
    }
    /* 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
      || acc->force_nat)
    {
        /* Parse out the NAT IP and Port components.
        */
        if(acc->force_nat)
        {
            strlcpy(nat_ip, acc->force_nat_ip, MAX_IPV4_STR_LEN);
            nat_port = acc->force_nat_port;
        }
        else
        {
            ndx = strchr(spadat->nat_access, ',');
            if(ndx != NULL)
            {
                strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1);
                nat_port = atoi(ndx+1);
            }
        }

        if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG)
        {
            /* Need to add an ACCEPT rule into the INPUT chain
            */
            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,
                fst_proto,
                spadat->use_src_ip,
                nat_port,
                exp_ts,
                in_chain->target
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                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 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);

        }
        else if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
        {
            /* Make our FORWARD and NAT rules, and make sure the
             * required jump rule exists
            */
            if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
                add_jump_rule(opts, 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
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                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 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(opts, 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
            );

            res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);

            if (opts->verbose)
                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 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 (opts->verbose)
                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 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);
        }
    }

    /* Done with the port list for access rules.
    */
    free_acc_port_list(port_list);

    return(res);
}