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 add_jump_rule(const fko_srv_options_t *opts, const int chain_num)
62 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS,
64 fwc.chain[chain_num].table,
65 fwc.chain[chain_num].from_chain,
66 fwc.chain[chain_num].jump_rule_pos,
67 fwc.chain[chain_num].to_chain
70 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
73 log_msg(LOG_INFO, "add_jump_rule() CMD: '%s' (res: %d, err: %s)",
74 cmd_buf, res, err_buf);
76 if(EXTCMD_IS_SUCCESS(res))
77 log_msg(LOG_INFO, "Added jump rule from chain: %s to chain: %s",
78 fwc.chain[chain_num].from_chain,
79 fwc.chain[chain_num].to_chain);
81 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
87 jump_rule_exists(const int chain_num)
90 char cmd_buf[CMD_BUFSIZE] = {0};
91 char target[CMD_BUFSIZE] = {0};
92 char line_buf[CMD_BUFSIZE] = {0};
95 sprintf(cmd_buf, "%s " IPT_LIST_RULES_ARGS,
97 fwc.chain[chain_num].table,
98 fwc.chain[chain_num].from_chain
101 ipt = popen(cmd_buf, "r");
106 "Got error %i trying to get rules list.\n", errno);
110 while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL)
112 /* Get past comments and empty lines (note: we only look at the
115 if(IS_EMPTY_LINE(line_buf[0]))
118 if(sscanf(line_buf, "%i %s ", &num, target) == 2)
120 if(strcmp(target, fwc.chain[chain_num].to_chain) == 0)
133 /* Print all firewall rules currently instantiated by the running fwknopd
137 fw_dump_rules(const fko_srv_options_t *opts)
140 int res, got_err = 0;
142 struct fw_chain *ch = opts->fw_config->chain;
144 if (opts->fw_list_all == 1)
146 fprintf(stdout, "Listing all iptables rules in applicable tables...\n");
149 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
152 if(fwc.chain[i].target[0] == '\0')
157 /* Create the list command
159 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_ALL_RULES_ARGS,
160 opts->fw_config->fw_command,
164 res = system(cmd_buf);
167 log_msg(LOG_INFO, "fw_dump_rules() CMD: '%s' (res: %d)",
170 /* Expect full success on this */
171 if(! EXTCMD_IS_SUCCESS(res))
173 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
180 fprintf(stdout, "Listing rules in fwknopd iptables chains...\n");
183 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
186 if(fwc.chain[i].target[0] == '\0')
191 /* Create the list command
193 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
194 opts->fw_config->fw_command,
199 res = system(cmd_buf);
202 log_msg(LOG_INFO, "fw_dump_rules() CMD: '%s' (res: %d)",
205 /* Expect full success on this */
206 if(! EXTCMD_IS_SUCCESS(res))
208 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
217 /* Quietly flush and delete all fwknop custom chains.
220 delete_all_chains(const fko_srv_options_t *opts)
225 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
227 if(fwc.chain[i].target[0] == '\0')
230 /* First look for a jump rule to this chain and remove it if it
233 if((jump_rule_num = jump_rule_exists(i)) > 0)
237 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
240 fwc.chain[i].from_chain,
244 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
247 log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
248 cmd_buf, res, err_buf);
250 /* Expect full success on this */
251 if(! EXTCMD_IS_SUCCESS(res))
252 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
257 /* Now flush and remove the chain.
259 snprintf(cmd_buf, CMD_BUFSIZE-1,
260 "(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1",
263 fwc.chain[i].to_chain,
266 fwc.chain[i].to_chain
269 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
272 log_msg(LOG_INFO, "delete_all_chains() CMD: '%s' (res: %d, err: %s)",
273 cmd_buf, res, err_buf);
275 /* Expect full success on this */
276 if(! EXTCMD_IS_SUCCESS(res))
277 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
281 /* Create the fwknop custom chains (at least those that are configured).
284 create_fw_chains(const fko_srv_options_t *opts)
287 int res, got_err = 0;
289 for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++)
291 if(fwc.chain[i].target[0] == '\0')
296 /* Create the custom chain.
298 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS,
301 fwc.chain[i].to_chain
304 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
307 log_msg(LOG_INFO, "create_fw_chains() CMD: '%s' (res: %d, err: %s)",
308 cmd_buf, res, err_buf);
310 /* Expect full success on this */
311 if(! EXTCMD_IS_SUCCESS(res))
313 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
317 /* Then create the jump rule to that chain.
319 res = add_jump_rule(opts, i);
321 /* Expect full success on this */
322 if(! EXTCMD_IS_SUCCESS(res))
331 set_fw_chain_conf(const int type, char *conf_str)
334 char tbuf[1024] = {0};
335 char *ndx = conf_str;
337 char *chain_fields[FW_NUM_CHAIN_FIELDS];
339 struct fw_chain *chain = &(fwc.chain[type]);
344 chain_fields[0] = tbuf;
355 chain_fields[j++] = &(tbuf[++i]);
363 /* Sanity check - j should be the number of chain fields
364 * (excluding the type).
366 if(j != FW_NUM_CHAIN_FIELDS)
368 fprintf(stderr, "[*] Custom Chain config parse error.\n"
369 "Wrong number of fields for chain type %i\n"
370 "Line: %s\n", type, conf_str);
374 /* Pull and set Target */
375 strlcpy(chain->target, chain_fields[0], MAX_TARGET_NAME_LEN);
377 /* Pull and set Table */
378 strlcpy(chain->table, chain_fields[1], MAX_TABLE_NAME_LEN);
380 /* Pull and set From_chain */
381 strlcpy(chain->from_chain, chain_fields[2], MAX_CHAIN_NAME_LEN);
383 /* Pull and set Jump_rule_position */
384 chain->jump_rule_pos = atoi(chain_fields[3]);
386 /* Pull and set To_chain */
387 strlcpy(chain->to_chain, chain_fields[4], MAX_CHAIN_NAME_LEN);
389 /* Pull and set Jump_rule_position */
390 chain->rule_pos = atoi(chain_fields[5]);
395 fw_config_init(fko_srv_options_t *opts)
398 memset(&fwc, 0x0, sizeof(struct fw_config));
400 /* Set our firewall exe command path (iptables in most cases).
402 strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], MAX_PATH_LEN);
404 /* Pull the fwknop chain config info and setup our internal
405 * config struct. The IPT_INPUT is the only one that is
406 * required. The rest are optional.
408 set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]);
410 /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y
412 if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0)
413 set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]);
415 /* The remaining access chains require ENABLE_IPT_FORWARDING = Y
417 if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0)
420 set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]);
421 set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]);
423 /* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y
425 if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0)
427 /* If an SNAT_TRANSLATE_IP is specified use the SNAT_ACCESS mode.
428 * Otherwise, use MASQUERADE_ACCESS.
430 * XXX: --DSS: Not sure if using the TRANSLATE_IP parameter as
431 * the determining factor is the best why to handle
435 if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL
436 && strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
437 set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]);
439 set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]);
443 /* Let us find it via our opts struct as well.
445 opts->fw_config = &fwc;
451 fw_initialize(const fko_srv_options_t *opts)
455 /* Flush the chains (just in case) so we can start fresh.
457 delete_all_chains(opts);
459 /* Now create any configured chains.
461 res = create_fw_chains(opts);
465 fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n");
471 fw_cleanup(const fko_srv_options_t *opts)
473 delete_all_chains(opts);
477 /****************************************************************************/
479 /* Rule Processing - Create an access request...
482 process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
484 char nat_ip[MAX_IPV4_STR_LEN] = {0};
485 char snat_target[SNAT_TARGET_BUFSIZE] = {0};
488 unsigned int nat_port = 0;
490 acc_port_list_t *port_list = NULL;
491 acc_port_list_t *ple;
493 unsigned int fst_proto;
494 unsigned int fst_port;
496 struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);
497 struct fw_chain *out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]);
498 struct fw_chain *fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]);
499 struct fw_chain *dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]);
500 struct fw_chain *snat_chain; /* We assign this later (if we need to). */
506 /* Parse and expand our access message.
508 expand_acc_port_list(&port_list, spadat->spa_message_remain);
510 /* Start at the top of the proto-port list...
514 /* Remember the first proto/port combo in case we need them
515 * for NAT access requests.
517 fst_proto = ple->proto;
518 fst_port = ple->port;
520 /* Set our expire time value.
523 exp_ts = now + spadat->fw_access_timeout;
525 /* For straight access requests, we currently support multiple proto/port
528 if((spadat->message_type == FKO_ACCESS_MSG
529 || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG) && !acc->force_nat)
532 /* Check to make sure that the jump rules exist for each
535 if(jump_rule_exists(IPT_INPUT_ACCESS) == 0)
536 add_jump_rule(opts, IPT_INPUT_ACCESS);
538 if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
539 if(jump_rule_exists(IPT_OUTPUT_ACCESS) == 0)
540 add_jump_rule(opts, IPT_OUTPUT_ACCESS);
542 /* Create an access command for each proto/port for the source ip.
548 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
549 opts->fw_config->fw_command,
559 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
562 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
563 cmd_buf, res, err_buf);
565 if(EXTCMD_IS_SUCCESS(res))
567 log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
568 in_chain->to_chain, spadat->use_src_ip,
569 spadat->spa_message_remain, exp_ts
572 in_chain->active_rules++;
574 /* Reset the next expected expire time for this chain if it
577 if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
578 in_chain->next_expire = exp_ts;
581 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
583 /* If we have to make an corresponding OUTPUT rule if out_chain target
586 if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
590 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_OUT_RULE_ARGS,
591 opts->fw_config->fw_command,
601 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
604 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
605 cmd_buf, res, err_buf);
607 if(EXTCMD_IS_SUCCESS(res))
609 log_msg(LOG_INFO, "Added OUTPUT Rule to %s for %s, %s expires at %u",
610 out_chain->to_chain, spadat->use_src_ip,
611 spadat->spa_message_remain, exp_ts
614 out_chain->active_rules++;
616 /* Reset the next expected expire time for this chain if it
619 if(out_chain->next_expire < now || exp_ts < out_chain->next_expire)
620 out_chain->next_expire = exp_ts;
623 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
630 /* NAT requests... */
631 else if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
632 || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
633 || spadat->message_type == FKO_NAT_ACCESS_MSG
634 || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
637 /* Parse out the NAT IP and Port components.
641 strlcpy(nat_ip, acc->force_nat_ip, MAX_IPV4_STR_LEN);
642 nat_port = acc->force_nat_port;
646 ndx = strchr(spadat->nat_access, ',');
649 strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1);
650 nat_port = atoi(ndx+1);
654 if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG)
656 /* Need to add an ACCEPT rule into the INPUT chain
660 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
661 opts->fw_config->fw_command,
671 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
674 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
675 cmd_buf, res, err_buf);
677 if(EXTCMD_IS_SUCCESS(res))
679 log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
680 in_chain->to_chain, spadat->use_src_ip,
681 spadat->spa_message_remain, exp_ts
684 in_chain->active_rules++;
686 /* Reset the next expected expire time for this chain if it
689 if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
690 in_chain->next_expire = exp_ts;
693 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
697 /* Make our FORWARD and NAT rules
699 if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
702 /* Make sure the required jump rule exists
704 if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
705 add_jump_rule(opts, IPT_FORWARD_ACCESS);
709 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_FWD_RULE_ARGS,
710 opts->fw_config->fw_command,
721 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
724 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
725 cmd_buf, res, err_buf);
727 if(EXTCMD_IS_SUCCESS(res))
729 log_msg(LOG_INFO, "Added FORWARD Rule to %s for %s, %s expires at %u",
730 fwd_chain->to_chain, spadat->use_src_ip,
731 spadat->spa_message_remain, exp_ts
734 fwd_chain->active_rules++;
736 /* Reset the next expected expire time for this chain if it
739 if(fwd_chain->next_expire < now || exp_ts < fwd_chain->next_expire)
740 fwd_chain->next_expire = exp_ts;
743 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
746 if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
749 /* Make sure the required jump rule exists
751 if (jump_rule_exists(IPT_DNAT_ACCESS) == 0)
752 add_jump_rule(opts, IPT_DNAT_ACCESS);
756 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_DNAT_RULE_ARGS,
757 opts->fw_config->fw_command,
759 dnat_chain->to_chain,
769 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
772 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
773 cmd_buf, res, err_buf);
775 if(EXTCMD_IS_SUCCESS(res))
777 log_msg(LOG_INFO, "Added DNAT Rule to %s for %s, %s expires at %u",
778 dnat_chain->to_chain, spadat->use_src_ip,
779 spadat->spa_message_remain, exp_ts
782 dnat_chain->active_rules++;
784 /* Reset the next expected expire time for this chain if it
787 if(dnat_chain->next_expire < now || exp_ts < dnat_chain->next_expire)
788 dnat_chain->next_expire = exp_ts;
791 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
794 /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well.
796 if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
800 /* Setup some parameter depending on whether we are using SNAT
803 if(strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
805 /* Using static SNAT */
806 snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
807 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
808 "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
813 /* Using MASQUERADE */
814 snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
815 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
816 "--to-ports %i", fst_port);
819 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_SNAT_RULE_ARGS,
820 opts->fw_config->fw_command,
822 snat_chain->to_chain,
831 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
834 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
835 cmd_buf, res, err_buf);
837 if(EXTCMD_IS_SUCCESS(res))
839 log_msg(LOG_INFO, "Added Source NAT Rule to %s for %s, %s expires at %u",
840 snat_chain->to_chain, spadat->use_src_ip,
841 spadat->spa_message_remain, exp_ts
844 snat_chain->active_rules++;
846 /* Reset the next expected expire time for this chain if it
849 if(snat_chain->next_expire < now || exp_ts < snat_chain->next_expire)
850 snat_chain->next_expire = exp_ts;
853 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
857 /* Done with the port list for access rules.
859 free_acc_port_list(port_list);
864 /* Iterate over the configure firewall access chains and purge expired
868 check_firewall_rules(const fko_srv_options_t *opts)
871 char rule_num_str[6];
872 char *ndx, *rn_start, *rn_end, *tmp_mark;
874 int i, res, rn_offset;
875 time_t now, rule_exp, min_exp = 0;
877 struct fw_chain *ch = opts->fw_config->chain;
881 /* Iterate over each chain and look for active rules to delete.
883 for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
885 /* If there are no active rules or we have not yet
886 * reached our expected next expire time, continue.
888 if(ch[i].active_rules == 0 || ch[i].next_expire > now)
895 /* There should be a rule to delete. Get the current list of
896 * rules for this chain and delete the ones that are expired.
898 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
899 opts->fw_config->fw_command,
904 res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
907 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
908 cmd_buf, res, err_buf);
910 if(!EXTCMD_IS_SUCCESS(res))
912 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
916 if(opts->verbose > 1)
917 log_msg(LOG_INFO, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out);
919 ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);
922 /* we did not find an expected rule.
925 "Did not find expire comment in rules list %i.\n", i);
927 if (ch[i].active_rules > 0)
928 ch[i].active_rules--;
933 /* walk the list and process rules as needed.
935 while (ndx != NULL) {
936 /* Jump forward and extract the timestamp
938 ndx += strlen(EXPIRE_COMMENT_PREFIX);
940 /* remember this spot for when we look for the next
945 strlcpy(exp_str, ndx, 11);
946 rule_exp = (time_t)atoll(exp_str);
950 /* Backtrack and get the rule number and delete it.
953 while(--rn_start > cmd_out)
955 if(*rn_start == '\n')
959 if(*rn_start != '\n')
961 /* This should not happen. But if it does, complain,
962 * decrement the active rule value, and go on.
965 "Rule parse error while finding rule line start in chain %i", i);
967 if (ch[i].active_rules > 0)
968 ch[i].active_rules--;
974 rn_end = strchr(rn_start, ' ');
977 /* This should not happen. But if it does, complain,
978 * decrement the active rule value, and go on.
981 "Rule parse error while finding rule number in chain %i", i);
983 if (ch[i].active_rules > 0)
984 ch[i].active_rules--;
989 strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);
993 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
994 opts->fw_config->fw_command,
997 atoi(rule_num_str) - rn_offset
1001 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
1004 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
1005 cmd_buf, res, err_buf);
1007 if(EXTCMD_IS_SUCCESS(res))
1009 log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u.",
1010 rule_num_str, ch[i].to_chain, rule_exp
1015 if (ch[i].active_rules > 0)
1016 ch[i].active_rules--;
1019 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
1024 /* Track the minimum future rule expire time.
1027 min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
1030 /* Push our tracking index forward beyond (just processed) _exp_
1031 * string so we can continue to the next rule in the list.
1033 ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
1036 /* Set the next pending expire time accordingly. 0 if there are no
1037 * more rules, or whatever the next expected (min_exp) time will be.
1039 if(ch[i].active_rules < 1)
1040 ch[i].next_expire = 0;
1042 ch[i].next_expire = min_exp;
1046 #endif /* FIREWALL_IPTABLES */