/* Expand any access entries that may be multi-value. */ static void expand_acc_ent_lists(fko_srv_options_t *opts) { acc_stanza_t *acc = opts->acc_stanzas; /* We need to do this for each stanza. */ while(acc) { /* Expand the source string to 32-bit integer masks foreach entry. */ expand_acc_source(acc); /* Now expand the open_ports string. */ if(acc->open_ports != NULL && strlen(acc->open_ports)) expand_acc_port_list(&(acc->oport_list), acc->open_ports); if(acc->restrict_ports != NULL && strlen(acc->restrict_ports)) expand_acc_port_list(&(acc->rport_list), acc->restrict_ports); /* Expand the GPG_REMOTE_ID string. */ if(acc->gpg_remote_id != NULL && strlen(acc->gpg_remote_id)) expand_acc_string_list(&(acc->gpg_remote_id_list), acc->gpg_remote_id); acc = acc->next; } }
/* 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) { /* TODO: Implement me */ char nat_ip[MAX_IPV4_STR_LEN] = {0}; char *ndx; unsigned int nat_port = 0;; 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; /* TODO: Implement me */ return(res); }
/* 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 new_rule[MAX_PF_NEW_RULE_LEN]; char write_cmd[CMD_BUFSIZE]; FILE *pfctl_fd = NULL; 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) { /* 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 " PF_LIST_ANCHOR_RULES_ARGS, opts->fw_config->fw_command, opts->fw_config->anchor ); /* Cache the current anchor rule set */ res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0); /* Build the new rule string */ memset(new_rule, 0x0, MAX_PF_NEW_RULE_LEN); snprintf(new_rule, MAX_PF_NEW_RULE_LEN-1, PF_ADD_RULE_ARGS "\n", ple->proto, spadat->use_src_ip, ple->port, exp_ts ); if (strlen(cmd_out) + strlen(new_rule) < STANDARD_CMD_OUT_BUFSIZE) { /* We add the rule to the running policy */ strlcat(cmd_out, new_rule, STANDARD_CMD_OUT_BUFSIZE); 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(-1); } if (fwrite(cmd_out, strlen(cmd_out), 1, pfctl_fd) == 1) { log_msg(LOG_INFO, "Added Rule for %s, %s expires at %u", spadat->use_src_ip, spadat->spa_message_remain, exp_ts ); fwc.active_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_WARNING, "Could not write rule to pf anchor"); pclose(pfctl_fd); } else { /* We don't have enough room to add the new firewall rule, * so throw a warning and bail. Once some of the existing * rules are expired the user will once again be able to gain * access. Note that we don't expect to really ever hit this * limit because of STANDARD_CMD_OUT_BUFSIZE is quite a number * of anchor rules. */ log_msg(LOG_WARNING, "Max anchor rules reached, try again later."); return 0; } 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); }
/* 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); }
/* 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) { char nat_ip[MAX_IPV4_STR_LEN] = {0}; unsigned int nat_port = 0; unsigned int fst_proto; unsigned int fst_port; struct fw_chain * const in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); struct fw_chain * const out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]); struct fw_chain * const fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]); struct fw_chain * const dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]); acc_port_list_t *port_list = NULL; acc_port_list_t *ple = NULL; char *ndx = NULL; int res = 0, is_err; 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) { /* technically we would already have exited with an error if there were * any memory allocation errors (see the add_port_list() function), but * for completeness... */ free_acc_port_list(port_list); 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; /* deal with SPA packets that themselves request a NAT operation */ 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) { ndx = strchr(spadat->nat_access, ','); if(ndx != NULL) { strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1); if (! is_valid_ipv4_addr(nat_ip)) { log_msg(LOG_INFO, "Invalid NAT IP in SPA message"); free_acc_port_list(port_list); return res; } nat_port = strtol_wrapper(ndx+1, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_INFO, "Invalid NAT port in SPA message"); free_acc_port_list(port_list); res = is_err; return res; } } if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG) { ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip, (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), fst_proto, nat_port, in_chain, exp_ts, now, "local NAT", spadat->spa_message_remain); } else if(strlen(fwd_chain->to_chain)) { /* FORWARD access rule */ forward_access_rule(opts, acc, fwd_chain, nat_ip, nat_port, fst_proto, fst_port, spadat, exp_ts, now); } /* DNAT rule */ if(strlen(dnat_chain->to_chain) && !acc->disable_dnat) dnat_rule(opts, acc, dnat_chain, nat_ip, nat_port, fst_proto, fst_port, spadat, exp_ts, now); if(acc->force_snat) snat_rule(opts, acc, nat_ip, nat_port, fst_proto, fst_port, spadat, exp_ts, now); } else if(acc->force_nat) /* handle force NAT scenarios */ { strlcpy(nat_ip, acc->force_nat_ip, sizeof(nat_ip)); nat_port = acc->force_nat_port; /* FORWARD access rule */ if(strlen(fwd_chain->to_chain)) forward_access_rule(opts, acc, fwd_chain, nat_ip, nat_port, fst_proto, fst_port, spadat, exp_ts, now); /* DNAT rule */ if(strlen(dnat_chain->to_chain) && !acc->disable_dnat) dnat_rule(opts, acc, dnat_chain, nat_ip, nat_port, fst_proto, fst_port, spadat, exp_ts, now); /* SNAT rule if required - we only allow this for FORCE_NAT * access stanzas for now until a new SPA packet type is added. */ if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0) snat_rule(opts, acc, nat_ip, nat_port, fst_proto, fst_port, spadat, exp_ts, now); } else /* Non-NAT request - this is the typical case. */ { /* Create an access command for each proto/port for the source ip. */ while(ple != NULL) { ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip, (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), ple->proto, ple->port, in_chain, exp_ts, now, "access", spadat->spa_message_remain); /* We need to make a corresponding OUTPUT rule if out_chain target * is not NULL. */ if(strlen(out_chain->to_chain)) { ipt_rule(opts, NULL, IPT_OUT_RULE_ARGS, spadat->use_src_ip, (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), ple->proto, ple->port, out_chain, exp_ts, now, "OUTPUT", spadat->spa_message_remain); } ple = ple->next; } } /* Done with the port list for access rules. */ free_acc_port_list(port_list); return(res); }
/* 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) { char nat_ip[MAX_IPV4_STR_LEN] = {0}; char snat_target[SNAT_TARGET_BUFSIZE] = {0}; char rule_buf[CMD_BUFSIZE] = {0}; char *ndx; unsigned int nat_port = 0; acc_port_list_t *port_list = NULL; acc_port_list_t *ple = NULL; unsigned int fst_proto; unsigned int fst_port; struct fw_chain * const in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); struct fw_chain * const out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]); struct fw_chain * const fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]); struct fw_chain * const 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, is_err, snat_chain_num = 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) { /* technically we would already have exited with an error if there were * any memory allocation errors (see the add_port_list() function), but * for completeness... */ free_acc_port_list(port_list); 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(chain_exists(opts, IPT_INPUT_ACCESS) == 0) create_chain(opts, IPT_INPUT_ACCESS); if(jump_rule_exists(opts, IPT_INPUT_ACCESS) == 0) add_jump_rule(opts, IPT_INPUT_ACCESS); if(strlen(out_chain->to_chain)) { if(chain_exists(opts, IPT_OUTPUT_ACCESS) == 0) create_chain(opts, IPT_OUTPUT_ACCESS); if(jump_rule_exists(opts, 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) { memset(rule_buf, 0, CMD_BUFSIZE); snprintf(rule_buf, CMD_BUFSIZE-1, IPT_RULE_ARGS, in_chain->table, ple->proto, spadat->use_src_ip, ple->port, exp_ts, in_chain->target ); if(rule_exists(opts, in_chain, rule_buf, ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) { if(create_rule(opts, in_chain->to_chain, rule_buf)) { 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; } } /* If we have to make an corresponding OUTPUT rule if out_chain target * is not NULL. */ if(strlen(out_chain->to_chain)) { memset(rule_buf, 0, CMD_BUFSIZE); snprintf(rule_buf, CMD_BUFSIZE-1, IPT_OUT_RULE_ARGS, out_chain->table, ple->proto, spadat->use_src_ip, ple->port, exp_ts, out_chain->target ); if(rule_exists(opts, out_chain, rule_buf, ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) { if(create_rule(opts, out_chain->to_chain, rule_buf)) { log_msg(LOG_INFO, "Added Rule in %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; } } } 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, sizeof(nat_ip)); 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); if (! is_valid_ipv4_addr(nat_ip)) { log_msg(LOG_INFO, "Invalid NAT IP in SPA message"); free_acc_port_list(port_list); return res; } nat_port = strtol_wrapper(ndx+1, 0, MAX_PORT, NO_EXIT_UPON_ERR, &is_err); if(is_err != FKO_SUCCESS) { log_msg(LOG_INFO, "Invalid NAT port in SPA message"); free_acc_port_list(port_list); res = is_err; return res; } } } if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG) { memset(rule_buf, 0, CMD_BUFSIZE); snprintf(rule_buf, CMD_BUFSIZE-1, IPT_RULE_ARGS, in_chain->table, fst_proto, spadat->use_src_ip, nat_port, exp_ts, in_chain->target ); /* Check to make sure that the jump rules exist for each * required chain */ if(chain_exists(opts, IPT_INPUT_ACCESS) == 0) create_chain(opts, IPT_INPUT_ACCESS); if(jump_rule_exists(opts, IPT_INPUT_ACCESS) == 0) add_jump_rule(opts, IPT_INPUT_ACCESS); if(rule_exists(opts, in_chain, rule_buf, fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0) { if(create_rule(opts, in_chain->to_chain, rule_buf)) { 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 if(strlen(fwd_chain->to_chain)) { /* Make our FORWARD and NAT rules, and make sure the * required chain and jump rule exists */ if(chain_exists(opts, IPT_FORWARD_ACCESS) == 0) create_chain(opts, IPT_FORWARD_ACCESS); if (jump_rule_exists(opts, IPT_FORWARD_ACCESS) == 0) add_jump_rule(opts, IPT_FORWARD_ACCESS); memset(rule_buf, 0, CMD_BUFSIZE); snprintf(rule_buf, CMD_BUFSIZE-1, IPT_FWD_RULE_ARGS, fwd_chain->table, fst_proto, spadat->use_src_ip, nat_ip, nat_port, exp_ts, fwd_chain->target ); if(rule_exists(opts, fwd_chain, rule_buf, fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0) { if(create_rule(opts, fwd_chain->to_chain, rule_buf)) { 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; } } } if(strlen(dnat_chain->to_chain)) { /* Make sure the required chain and jump rule exist */ if(chain_exists(opts, IPT_DNAT_ACCESS) == 0) create_chain(opts, IPT_DNAT_ACCESS); if (jump_rule_exists(opts, IPT_DNAT_ACCESS) == 0) add_jump_rule(opts, IPT_DNAT_ACCESS); memset(rule_buf, 0, CMD_BUFSIZE); snprintf(rule_buf, CMD_BUFSIZE-1, IPT_DNAT_RULE_ARGS, dnat_chain->table, fst_proto, spadat->use_src_ip, fst_port, exp_ts, dnat_chain->target, nat_ip, nat_port ); if(rule_exists(opts, dnat_chain, rule_buf, fst_proto, spadat->use_src_ip, fst_port, exp_ts) == 0) { if(create_rule(opts, dnat_chain->to_chain, rule_buf)) { 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; } } } /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well. */ if(acc->force_snat || strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0) { /* Add SNAT or MASQUERADE rules. */ if(acc->force_snat && is_valid_ipv4_addr(acc->force_snat_ip)) { /* Using static SNAT */ snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]); snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, "--to-source %s:%i", acc->force_snat_ip, fst_port); snat_chain_num = IPT_SNAT_ACCESS; } else if(acc->force_snat && acc->force_masquerade) { /* Using MASQUERADE */ snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]); snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, "--to-ports %i", fst_port); snat_chain_num = IPT_MASQUERADE_ACCESS; } else if((opts->config[CONF_SNAT_TRANSLATE_IP] != NULL) && is_valid_ipv4_addr(opts->config[CONF_SNAT_TRANSLATE_IP])) { /* 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); snat_chain_num = IPT_SNAT_ACCESS; } else { /* Using MASQUERADE */ snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]); snprintf(snat_target, SNAT_TARGET_BUFSIZE-1, "--to-ports %i", fst_port); snat_chain_num = IPT_MASQUERADE_ACCESS; } if(chain_exists(opts, snat_chain_num) == 0) create_chain(opts, snat_chain_num); if(jump_rule_exists(opts, snat_chain_num) == 0) add_jump_rule(opts, snat_chain_num); memset(rule_buf, 0, CMD_BUFSIZE); snprintf(rule_buf, CMD_BUFSIZE-1, IPT_SNAT_RULE_ARGS, snat_chain->table, fst_proto, nat_ip, nat_port, exp_ts, snat_chain->target, snat_target ); if(rule_exists(opts, snat_chain, rule_buf, fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0) { if(create_rule(opts, snat_chain->to_chain, rule_buf)) { log_msg(LOG_INFO, "Added SNAT 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; } } } } /* Done with the port list for access rules. */ free_acc_port_list(port_list); return(res); }
/* 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); }