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);
696 else if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
698 /* Make our FORWARD and NAT rules, and make sure the
699 * required jump rule exists
701 if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
702 add_jump_rule(opts, IPT_FORWARD_ACCESS);
706 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_FWD_RULE_ARGS,
707 opts->fw_config->fw_command,
718 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
721 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
722 cmd_buf, res, err_buf);
724 if(EXTCMD_IS_SUCCESS(res))
726 log_msg(LOG_INFO, "Added FORWARD Rule to %s for %s, %s expires at %u",
727 fwd_chain->to_chain, spadat->use_src_ip,
728 spadat->spa_message_remain, exp_ts
731 fwd_chain->active_rules++;
733 /* Reset the next expected expire time for this chain if it
736 if(fwd_chain->next_expire < now || exp_ts < fwd_chain->next_expire)
737 fwd_chain->next_expire = exp_ts;
740 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
743 if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
746 /* Make sure the required jump rule exists
748 if (jump_rule_exists(IPT_DNAT_ACCESS) == 0)
749 add_jump_rule(opts, IPT_DNAT_ACCESS);
753 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_DNAT_RULE_ARGS,
754 opts->fw_config->fw_command,
756 dnat_chain->to_chain,
766 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
769 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
770 cmd_buf, res, err_buf);
772 if(EXTCMD_IS_SUCCESS(res))
774 log_msg(LOG_INFO, "Added DNAT Rule to %s for %s, %s expires at %u",
775 dnat_chain->to_chain, spadat->use_src_ip,
776 spadat->spa_message_remain, exp_ts
779 dnat_chain->active_rules++;
781 /* Reset the next expected expire time for this chain if it
784 if(dnat_chain->next_expire < now || exp_ts < dnat_chain->next_expire)
785 dnat_chain->next_expire = exp_ts;
788 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
791 /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well.
793 if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
797 /* Setup some parameter depending on whether we are using SNAT
800 if(strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
802 /* Using static SNAT */
803 snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
804 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
805 "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
810 /* Using MASQUERADE */
811 snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
812 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
813 "--to-ports %i", fst_port);
816 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_SNAT_RULE_ARGS,
817 opts->fw_config->fw_command,
819 snat_chain->to_chain,
828 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
831 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
832 cmd_buf, res, err_buf);
834 if(EXTCMD_IS_SUCCESS(res))
836 log_msg(LOG_INFO, "Added Source NAT Rule to %s for %s, %s expires at %u",
837 snat_chain->to_chain, spadat->use_src_ip,
838 spadat->spa_message_remain, exp_ts
841 snat_chain->active_rules++;
843 /* Reset the next expected expire time for this chain if it
846 if(snat_chain->next_expire < now || exp_ts < snat_chain->next_expire)
847 snat_chain->next_expire = exp_ts;
850 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
854 /* Done with the port list for access rules.
856 free_acc_port_list(port_list);
861 /* Iterate over the configure firewall access chains and purge expired
865 check_firewall_rules(const fko_srv_options_t *opts)
868 char rule_num_str[6];
869 char *ndx, *rn_start, *rn_end, *tmp_mark;
871 int i, res, rn_offset;
872 time_t now, rule_exp, min_exp = 0;
874 struct fw_chain *ch = opts->fw_config->chain;
878 /* Iterate over each chain and look for active rules to delete.
880 for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
882 /* If there are no active rules or we have not yet
883 * reached our expected next expire time, continue.
885 if(ch[i].active_rules == 0 || ch[i].next_expire > now)
892 /* There should be a rule to delete. Get the current list of
893 * rules for this chain and delete the ones that are expired.
895 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
896 opts->fw_config->fw_command,
901 res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
904 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
905 cmd_buf, res, err_buf);
907 if(!EXTCMD_IS_SUCCESS(res))
909 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
913 if(opts->verbose > 1)
914 log_msg(LOG_INFO, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out);
916 ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);
919 /* we did not find an expected rule.
922 "Did not find expire comment in rules list %i.\n", i);
924 if (ch[i].active_rules > 0)
925 ch[i].active_rules--;
930 /* walk the list and process rules as needed.
932 while (ndx != NULL) {
933 /* Jump forward and extract the timestamp
935 ndx += strlen(EXPIRE_COMMENT_PREFIX);
937 /* remember this spot for when we look for the next
942 strlcpy(exp_str, ndx, 11);
943 rule_exp = (time_t)atoll(exp_str);
947 /* Backtrack and get the rule number and delete it.
950 while(--rn_start > cmd_out)
952 if(*rn_start == '\n')
956 if(*rn_start != '\n')
958 /* This should not happen. But if it does, complain,
959 * decrement the active rule value, and go on.
962 "Rule parse error while finding rule line start in chain %i", i);
964 if (ch[i].active_rules > 0)
965 ch[i].active_rules--;
971 rn_end = strchr(rn_start, ' ');
974 /* This should not happen. But if it does, complain,
975 * decrement the active rule value, and go on.
978 "Rule parse error while finding rule number in chain %i", i);
980 if (ch[i].active_rules > 0)
981 ch[i].active_rules--;
986 strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);
990 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
991 opts->fw_config->fw_command,
994 atoi(rule_num_str) - rn_offset
998 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
1001 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
1002 cmd_buf, res, err_buf);
1004 if(EXTCMD_IS_SUCCESS(res))
1006 log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u.",
1007 rule_num_str, ch[i].to_chain, rule_exp
1012 if (ch[i].active_rules > 0)
1013 ch[i].active_rules--;
1016 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
1021 /* Track the minimum future rule expire time.
1024 min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
1027 /* Push our tracking index forward beyond (just processed) _exp_
1028 * string so we can continue to the next rule in the list.
1030 ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
1033 /* Set the next pending expire time accordingly. 0 if there are no
1034 * more rules, or whatever the next expected (min_exp) time will be.
1036 if(ch[i].active_rules < 1)
1037 ch[i].next_expire = 0;
1039 ch[i].next_expire = min_exp;
1043 #endif /* FIREWALL_IPTABLES */