2 *****************************************************************************
4 * File: fw_util_iptables.c
6 * Author: Damien S. Stuart
8 * Purpose: Fwknop routines for managing iptables firewall rules.
10 * Copyright 2010 Damien Stuart (dstuart@dstuart.org)
12 * License (GNU Public License):
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 *****************************************************************************
32 #include "fwknopd_common.h"
34 #ifdef FIREWALL_IPTABLES
42 static struct fw_config fwc;
43 static char cmd_buf[CMD_BUFSIZE];
44 static char err_buf[CMD_BUFSIZE];
45 static char cmd_out[STANDARD_CMD_OUT_BUFSIZE];
48 zero_cmd_buffers(void)
50 memset(cmd_buf, 0x0, CMD_BUFSIZE);
51 memset(err_buf, 0x0, CMD_BUFSIZE);
52 memset(cmd_out, 0x0, STANDARD_CMD_OUT_BUFSIZE);
56 comment_match_exists(const fko_srv_options_t *opts)
60 struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);
64 /* Add a harmless rule to the iptables OUTPUT chain that uses the comment
65 * match and make sure it exists. If not, return zero. Otherwise, delete
66 * the rule and return true.
68 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_TMP_COMMENT_ARGS,
69 opts->fw_config->fw_command,
76 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
79 log_msg(LOG_INFO, "comment_match_exists() CMD: '%s' (res: %d, err: %s)",
80 cmd_buf, res, err_buf);
84 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
85 opts->fw_config->fw_command,
90 res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
92 if(!EXTCMD_IS_SUCCESS(res))
93 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
95 ndx = strstr(cmd_out, TMP_COMMENT);
97 res = 0; /* did not find the tmp comment */
103 /* Delete the tmp comment rule
107 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
108 opts->fw_config->fw_command,
113 run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
120 add_jump_rule(const fko_srv_options_t *opts, const int chain_num)
126 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS,
128 fwc.chain[chain_num].table,
129 fwc.chain[chain_num].from_chain,
130 fwc.chain[chain_num].jump_rule_pos,
131 fwc.chain[chain_num].to_chain
134 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
137 log_msg(LOG_INFO, "add_jump_rule() CMD: '%s' (res: %d, err: %s)",
138 cmd_buf, res, err_buf);
140 if(EXTCMD_IS_SUCCESS(res))
141 log_msg(LOG_INFO, "Added jump rule from chain: %s to chain: %s",
142 fwc.chain[chain_num].from_chain,
143 fwc.chain[chain_num].to_chain);
145 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
151 jump_rule_exists(const int chain_num)
154 char cmd_buf[CMD_BUFSIZE] = {0};
155 char target[CMD_BUFSIZE] = {0};
156 char line_buf[CMD_BUFSIZE] = {0};
159 sprintf(cmd_buf, "%s " IPT_LIST_RULES_ARGS,
161 fwc.chain[chain_num].table,
162 fwc.chain[chain_num].from_chain
165 ipt = popen(cmd_buf, "r");
170 "Got error %i trying to get rules list.\n", errno);
174 while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL)
176 /* Get past comments and empty lines (note: we only look at the
179 if(IS_EMPTY_LINE(line_buf[0]))
182 if(sscanf(line_buf, "%i %s ", &num, target) == 2)
184 if(strcmp(target, fwc.chain[chain_num].to_chain) == 0)
197 /* Print all firewall rules currently instantiated by the running fwknopd
201 fw_dump_rules(const fko_srv_options_t *opts)
204 int res, got_err = 0;
206 struct fw_chain *ch = opts->fw_config->chain;
208 if (opts->fw_list_all == 1)
210 fprintf(stdout, "Listing all iptables rules in applicable tables...\n");
213 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
216 if(fwc.chain[i].target[0] == '\0')
221 /* Create the list command
223 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_ALL_RULES_ARGS,
224 opts->fw_config->fw_command,
228 res = system(cmd_buf);
231 log_msg(LOG_INFO, "fw_dump_rules() CMD: '%s' (res: %d)",
234 /* Expect full success on this */
235 if(! EXTCMD_IS_SUCCESS(res))
237 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
244 fprintf(stdout, "Listing rules in fwknopd iptables chains...\n");
247 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
250 if(fwc.chain[i].target[0] == '\0')
255 /* Create the list command
257 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
258 opts->fw_config->fw_command,
263 res = system(cmd_buf);
266 log_msg(LOG_INFO, "fw_dump_rules() CMD: '%s' (res: %d)",
269 /* Expect full success on this */
270 if(! EXTCMD_IS_SUCCESS(res))
272 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
281 /* Quietly flush and delete all fwknop custom chains.
284 delete_all_chains(const fko_srv_options_t *opts)
289 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
291 if(fwc.chain[i].target[0] == '\0')
294 /* First look for a jump rule to this chain and remove it if it
297 if((jump_rule_num = jump_rule_exists(i)) > 0)
301 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
304 fwc.chain[i].from_chain,
308 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
311 log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
312 cmd_buf, res, err_buf);
314 /* Expect full success on this */
315 if(! EXTCMD_IS_SUCCESS(res))
316 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
321 /* Now flush and remove the chain.
323 snprintf(cmd_buf, CMD_BUFSIZE-1,
324 "(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1",
327 fwc.chain[i].to_chain,
330 fwc.chain[i].to_chain
333 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
336 log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
337 cmd_buf, res, err_buf);
339 /* Expect full success on this */
340 if(! EXTCMD_IS_SUCCESS(res))
341 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
345 /* Create the fwknop custom chains (at least those that are configured).
348 create_fw_chains(const fko_srv_options_t *opts)
351 int res, got_err = 0;
353 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
355 if(fwc.chain[i].target[0] == '\0')
360 /* Create the custom chain.
362 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
365 fwc.chain[i].to_chain
368 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
371 log_msg(LOG_INFO, "create_fw_chains() CMD: '%s' (res: %d, err: %s)",
372 cmd_buf, res, err_buf);
374 /* Expect full success on this */
375 if(! EXTCMD_IS_SUCCESS(res))
377 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
381 /* Then create the jump rule to that chain.
383 res = add_jump_rule(opts, i);
385 /* Expect full success on this */
386 if(! EXTCMD_IS_SUCCESS(res))
395 set_fw_chain_conf(const int type, char *conf_str)
398 char tbuf[1024] = {0};
399 char *ndx = conf_str;
401 char *chain_fields[FW_NUM_CHAIN_FIELDS];
403 struct fw_chain *chain = &(fwc.chain[type]);
408 chain_fields[0] = tbuf;
419 chain_fields[j++] = &(tbuf[++i]);
427 /* Sanity check - j should be the number of chain fields
428 * (excluding the type).
430 if(j != FW_NUM_CHAIN_FIELDS)
432 fprintf(stderr, "[*] Custom Chain config parse error.\n"
433 "Wrong number of fields for chain type %i\n"
434 "Line: %s\n", type, conf_str);
438 /* Pull and set Target */
439 strlcpy(chain->target, chain_fields[0], MAX_TARGET_NAME_LEN);
441 /* Pull and set Table */
442 strlcpy(chain->table, chain_fields[1], MAX_TABLE_NAME_LEN);
444 /* Pull and set From_chain */
445 strlcpy(chain->from_chain, chain_fields[2], MAX_CHAIN_NAME_LEN);
447 /* Pull and set Jump_rule_position */
448 chain->jump_rule_pos = atoi(chain_fields[3]);
450 /* Pull and set To_chain */
451 strlcpy(chain->to_chain, chain_fields[4], MAX_CHAIN_NAME_LEN);
453 /* Pull and set Jump_rule_position */
454 chain->rule_pos = atoi(chain_fields[5]);
459 fw_config_init(fko_srv_options_t *opts)
462 memset(&fwc, 0x0, sizeof(struct fw_config));
464 /* Set our firewall exe command path (iptables in most cases).
466 strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], MAX_PATH_LEN);
468 /* Pull the fwknop chain config info and setup our internal
469 * config struct. The IPT_INPUT is the only one that is
470 * required. The rest are optional.
472 set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]);
474 /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y
476 if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0)
477 set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]);
479 /* The remaining access chains require ENABLE_IPT_FORWARDING = Y
481 if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0)
484 set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]);
485 set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]);
487 /* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y
489 if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0)
491 /* If an SNAT_TRANSLATE_IP is specified use the SNAT_ACCESS mode.
492 * Otherwise, use MASQUERADE_ACCESS.
494 * XXX: --DSS: Not sure if using the TRANSLATE_IP parameter as
495 * the determining factor is the best why to handle
499 if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL
500 && strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
501 set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]);
503 set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]);
507 /* Let us find it via our opts struct as well.
509 opts->fw_config = &fwc;
515 fw_initialize(const fko_srv_options_t *opts)
519 /* Flush the chains (just in case) so we can start fresh.
521 if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_INIT], "Y", 1) == 0)
522 delete_all_chains(opts);
524 /* Now create any configured chains.
526 res = create_fw_chains(opts);
530 fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n");
534 /* Make sure that the 'comment' match is available
536 if((strncasecmp(opts->config[CONF_ENABLE_IPT_COMMENT_CHECK], "Y", 1) == 0)
537 && (comment_match_exists(opts) != 1))
539 fprintf(stderr, "Warning: Could not use the 'comment' match.\n");
545 fw_cleanup(const fko_srv_options_t *opts)
547 if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_EXIT], "N", 1) == 0)
550 delete_all_chains(opts);
554 /****************************************************************************/
556 /* Rule Processing - Create an access request...
559 process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
561 char nat_ip[MAX_IPV4_STR_LEN] = {0};
562 char snat_target[SNAT_TARGET_BUFSIZE] = {0};
565 unsigned int nat_port = 0;
567 acc_port_list_t *port_list = NULL;
568 acc_port_list_t *ple;
570 unsigned int fst_proto;
571 unsigned int fst_port;
573 struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);
574 struct fw_chain *out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]);
575 struct fw_chain *fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]);
576 struct fw_chain *dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]);
577 struct fw_chain *snat_chain; /* We assign this later (if we need to). */
583 /* Parse and expand our access message.
585 if(expand_acc_port_list(&port_list, spadat->spa_message_remain) != 1)
588 /* Start at the top of the proto-port list...
592 /* Remember the first proto/port combo in case we need them
593 * for NAT access requests.
595 fst_proto = ple->proto;
596 fst_port = ple->port;
598 /* Set our expire time value.
601 exp_ts = now + spadat->fw_access_timeout;
603 /* For straight access requests, we currently support multiple proto/port
606 if((spadat->message_type == FKO_ACCESS_MSG
607 || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG) && !acc->force_nat)
610 /* Check to make sure that the jump rules exist for each
613 if(jump_rule_exists(IPT_INPUT_ACCESS) == 0)
614 add_jump_rule(opts, IPT_INPUT_ACCESS);
616 if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
617 if(jump_rule_exists(IPT_OUTPUT_ACCESS) == 0)
618 add_jump_rule(opts, IPT_OUTPUT_ACCESS);
620 /* Create an access command for each proto/port for the source ip.
626 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
627 opts->fw_config->fw_command,
637 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
640 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
641 cmd_buf, res, err_buf);
643 if(EXTCMD_IS_SUCCESS(res))
645 log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
646 in_chain->to_chain, spadat->use_src_ip,
647 spadat->spa_message_remain, exp_ts
650 in_chain->active_rules++;
652 /* Reset the next expected expire time for this chain if it
655 if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
656 in_chain->next_expire = exp_ts;
659 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
661 /* If we have to make an corresponding OUTPUT rule if out_chain target
664 if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
668 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_OUT_RULE_ARGS,
669 opts->fw_config->fw_command,
679 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
682 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
683 cmd_buf, res, err_buf);
685 if(EXTCMD_IS_SUCCESS(res))
687 log_msg(LOG_INFO, "Added OUTPUT Rule to %s for %s, %s expires at %u",
688 out_chain->to_chain, spadat->use_src_ip,
689 spadat->spa_message_remain, exp_ts
692 out_chain->active_rules++;
694 /* Reset the next expected expire time for this chain if it
697 if(out_chain->next_expire < now || exp_ts < out_chain->next_expire)
698 out_chain->next_expire = exp_ts;
701 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
708 /* NAT requests... */
709 else if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
710 || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
711 || spadat->message_type == FKO_NAT_ACCESS_MSG
712 || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
715 /* Parse out the NAT IP and Port components.
719 strlcpy(nat_ip, acc->force_nat_ip, MAX_IPV4_STR_LEN);
720 nat_port = acc->force_nat_port;
724 ndx = strchr(spadat->nat_access, ',');
727 strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1);
728 nat_port = atoi(ndx+1);
732 if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG)
734 /* Need to add an ACCEPT rule into the INPUT chain
738 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
739 opts->fw_config->fw_command,
749 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
752 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
753 cmd_buf, res, err_buf);
755 if(EXTCMD_IS_SUCCESS(res))
757 log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
758 in_chain->to_chain, spadat->use_src_ip,
759 spadat->spa_message_remain, exp_ts
762 in_chain->active_rules++;
764 /* Reset the next expected expire time for this chain if it
767 if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
768 in_chain->next_expire = exp_ts;
771 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
774 else if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
776 /* Make our FORWARD and NAT rules, and make sure the
777 * required jump rule exists
779 if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
780 add_jump_rule(opts, IPT_FORWARD_ACCESS);
784 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_FWD_RULE_ARGS,
785 opts->fw_config->fw_command,
796 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
799 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
800 cmd_buf, res, err_buf);
802 if(EXTCMD_IS_SUCCESS(res))
804 log_msg(LOG_INFO, "Added FORWARD Rule to %s for %s, %s expires at %u",
805 fwd_chain->to_chain, spadat->use_src_ip,
806 spadat->spa_message_remain, exp_ts
809 fwd_chain->active_rules++;
811 /* Reset the next expected expire time for this chain if it
814 if(fwd_chain->next_expire < now || exp_ts < fwd_chain->next_expire)
815 fwd_chain->next_expire = exp_ts;
818 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
821 if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
824 /* Make sure the required jump rule exists
826 if (jump_rule_exists(IPT_DNAT_ACCESS) == 0)
827 add_jump_rule(opts, IPT_DNAT_ACCESS);
831 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_DNAT_RULE_ARGS,
832 opts->fw_config->fw_command,
834 dnat_chain->to_chain,
844 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
847 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
848 cmd_buf, res, err_buf);
850 if(EXTCMD_IS_SUCCESS(res))
852 log_msg(LOG_INFO, "Added DNAT Rule to %s for %s, %s expires at %u",
853 dnat_chain->to_chain, spadat->use_src_ip,
854 spadat->spa_message_remain, exp_ts
857 dnat_chain->active_rules++;
859 /* Reset the next expected expire time for this chain if it
862 if(dnat_chain->next_expire < now || exp_ts < dnat_chain->next_expire)
863 dnat_chain->next_expire = exp_ts;
866 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
869 /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well.
871 if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
875 /* Setup some parameter depending on whether we are using SNAT
878 if(strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
880 /* Using static SNAT */
881 snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
882 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
883 "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
888 /* Using MASQUERADE */
889 snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
890 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
891 "--to-ports %i", fst_port);
894 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_SNAT_RULE_ARGS,
895 opts->fw_config->fw_command,
897 snat_chain->to_chain,
906 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
909 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
910 cmd_buf, res, err_buf);
912 if(EXTCMD_IS_SUCCESS(res))
914 log_msg(LOG_INFO, "Added Source NAT Rule to %s for %s, %s expires at %u",
915 snat_chain->to_chain, spadat->use_src_ip,
916 spadat->spa_message_remain, exp_ts
919 snat_chain->active_rules++;
921 /* Reset the next expected expire time for this chain if it
924 if(snat_chain->next_expire < now || exp_ts < snat_chain->next_expire)
925 snat_chain->next_expire = exp_ts;
928 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
932 /* Done with the port list for access rules.
934 free_acc_port_list(port_list);
939 /* Iterate over the configure firewall access chains and purge expired
943 check_firewall_rules(const fko_srv_options_t *opts)
946 char rule_num_str[6];
947 char *ndx, *rn_start, *rn_end, *tmp_mark;
949 int i, res, rn_offset;
950 time_t now, rule_exp, min_exp = 0;
952 struct fw_chain *ch = opts->fw_config->chain;
956 /* Iterate over each chain and look for active rules to delete.
958 for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
960 /* If there are no active rules or we have not yet
961 * reached our expected next expire time, continue.
963 if(ch[i].active_rules == 0 || ch[i].next_expire > now)
970 /* There should be a rule to delete. Get the current list of
971 * rules for this chain and delete the ones that are expired.
973 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
974 opts->fw_config->fw_command,
979 res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
982 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
983 cmd_buf, res, err_buf);
985 if(!EXTCMD_IS_SUCCESS(res))
987 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
991 if(opts->verbose > 1)
992 log_msg(LOG_INFO, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out);
994 ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);
997 /* we did not find an expected rule.
1000 "Did not find expire comment in rules list %i.\n", i);
1002 if (ch[i].active_rules > 0)
1003 ch[i].active_rules--;
1008 /* walk the list and process rules as needed.
1010 while (ndx != NULL) {
1011 /* Jump forward and extract the timestamp
1013 ndx += strlen(EXPIRE_COMMENT_PREFIX);
1015 /* remember this spot for when we look for the next
1020 strlcpy(exp_str, ndx, 11);
1021 rule_exp = (time_t)atoll(exp_str);
1025 /* Backtrack and get the rule number and delete it.
1028 while(--rn_start > cmd_out)
1030 if(*rn_start == '\n')
1034 if(*rn_start != '\n')
1036 /* This should not happen. But if it does, complain,
1037 * decrement the active rule value, and go on.
1040 "Rule parse error while finding rule line start in chain %i", i);
1042 if (ch[i].active_rules > 0)
1043 ch[i].active_rules--;
1049 rn_end = strchr(rn_start, ' ');
1052 /* This should not happen. But if it does, complain,
1053 * decrement the active rule value, and go on.
1056 "Rule parse error while finding rule number in chain %i", i);
1058 if (ch[i].active_rules > 0)
1059 ch[i].active_rules--;
1064 strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);
1068 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
1069 opts->fw_config->fw_command,
1072 atoi(rule_num_str) - rn_offset
1076 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
1079 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
1080 cmd_buf, res, err_buf);
1082 if(EXTCMD_IS_SUCCESS(res))
1084 log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u.",
1085 rule_num_str, ch[i].to_chain, rule_exp
1090 if (ch[i].active_rules > 0)
1091 ch[i].active_rules--;
1094 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
1099 /* Track the minimum future rule expire time.
1102 min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
1105 /* Push our tracking index forward beyond (just processed) _exp_
1106 * string so we can continue to the next rule in the list.
1108 ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
1111 /* Set the next pending expire time accordingly. 0 if there are no
1112 * more rules, or whatever the next expected (min_exp) time will be.
1114 if(ch[i].active_rules < 1)
1115 ch[i].next_expire = 0;
1117 ch[i].next_expire = min_exp;
1121 #endif /* FIREWALL_IPTABLES */