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 if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_INIT], "Y", 1) == 0)
458 delete_all_chains(opts);
460 /* Now create any configured chains.
462 res = create_fw_chains(opts);
466 fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n");
472 fw_cleanup(const fko_srv_options_t *opts)
474 if(strncasecmp(opts->config[CONF_FLUSH_IPT_AT_EXIT], "N", 1) == 0)
477 delete_all_chains(opts);
481 /****************************************************************************/
483 /* Rule Processing - Create an access request...
486 process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat)
488 char nat_ip[MAX_IPV4_STR_LEN] = {0};
489 char snat_target[SNAT_TARGET_BUFSIZE] = {0};
492 unsigned int nat_port = 0;
494 acc_port_list_t *port_list = NULL;
495 acc_port_list_t *ple;
497 unsigned int fst_proto;
498 unsigned int fst_port;
500 struct fw_chain *in_chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]);
501 struct fw_chain *out_chain = &(opts->fw_config->chain[IPT_OUTPUT_ACCESS]);
502 struct fw_chain *fwd_chain = &(opts->fw_config->chain[IPT_FORWARD_ACCESS]);
503 struct fw_chain *dnat_chain = &(opts->fw_config->chain[IPT_DNAT_ACCESS]);
504 struct fw_chain *snat_chain; /* We assign this later (if we need to). */
510 /* Parse and expand our access message.
512 expand_acc_port_list(&port_list, spadat->spa_message_remain);
514 /* Start at the top of the proto-port list...
518 /* Remember the first proto/port combo in case we need them
519 * for NAT access requests.
521 fst_proto = ple->proto;
522 fst_port = ple->port;
524 /* Set our expire time value.
527 exp_ts = now + spadat->fw_access_timeout;
529 /* For straight access requests, we currently support multiple proto/port
532 if((spadat->message_type == FKO_ACCESS_MSG
533 || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG) && !acc->force_nat)
536 /* Check to make sure that the jump rules exist for each
539 if(jump_rule_exists(IPT_INPUT_ACCESS) == 0)
540 add_jump_rule(opts, IPT_INPUT_ACCESS);
542 if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
543 if(jump_rule_exists(IPT_OUTPUT_ACCESS) == 0)
544 add_jump_rule(opts, IPT_OUTPUT_ACCESS);
546 /* Create an access command for each proto/port for the source ip.
552 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
553 opts->fw_config->fw_command,
563 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
566 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
567 cmd_buf, res, err_buf);
569 if(EXTCMD_IS_SUCCESS(res))
571 log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
572 in_chain->to_chain, spadat->use_src_ip,
573 spadat->spa_message_remain, exp_ts
576 in_chain->active_rules++;
578 /* Reset the next expected expire time for this chain if it
581 if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
582 in_chain->next_expire = exp_ts;
585 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
587 /* If we have to make an corresponding OUTPUT rule if out_chain target
590 if(out_chain->to_chain != NULL && strlen(out_chain->to_chain))
594 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_OUT_RULE_ARGS,
595 opts->fw_config->fw_command,
605 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
608 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
609 cmd_buf, res, err_buf);
611 if(EXTCMD_IS_SUCCESS(res))
613 log_msg(LOG_INFO, "Added OUTPUT Rule to %s for %s, %s expires at %u",
614 out_chain->to_chain, spadat->use_src_ip,
615 spadat->spa_message_remain, exp_ts
618 out_chain->active_rules++;
620 /* Reset the next expected expire time for this chain if it
623 if(out_chain->next_expire < now || exp_ts < out_chain->next_expire)
624 out_chain->next_expire = exp_ts;
627 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
634 /* NAT requests... */
635 else if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG
636 || spadat->message_type == FKO_CLIENT_TIMEOUT_LOCAL_NAT_ACCESS_MSG
637 || spadat->message_type == FKO_NAT_ACCESS_MSG
638 || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG
641 /* Parse out the NAT IP and Port components.
645 strlcpy(nat_ip, acc->force_nat_ip, MAX_IPV4_STR_LEN);
646 nat_port = acc->force_nat_port;
650 ndx = strchr(spadat->nat_access, ',');
653 strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1);
654 nat_port = atoi(ndx+1);
658 if(spadat->message_type == FKO_LOCAL_NAT_ACCESS_MSG)
660 /* Need to add an ACCEPT rule into the INPUT chain
664 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS,
665 opts->fw_config->fw_command,
675 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
678 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
679 cmd_buf, res, err_buf);
681 if(EXTCMD_IS_SUCCESS(res))
683 log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u",
684 in_chain->to_chain, spadat->use_src_ip,
685 spadat->spa_message_remain, exp_ts
688 in_chain->active_rules++;
690 /* Reset the next expected expire time for this chain if it
693 if(in_chain->next_expire < now || exp_ts < in_chain->next_expire)
694 in_chain->next_expire = exp_ts;
697 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
700 else if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain))
702 /* Make our FORWARD and NAT rules, and make sure the
703 * required jump rule exists
705 if (jump_rule_exists(IPT_FORWARD_ACCESS) == 0)
706 add_jump_rule(opts, IPT_FORWARD_ACCESS);
710 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_FWD_RULE_ARGS,
711 opts->fw_config->fw_command,
722 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
725 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
726 cmd_buf, res, err_buf);
728 if(EXTCMD_IS_SUCCESS(res))
730 log_msg(LOG_INFO, "Added FORWARD Rule to %s for %s, %s expires at %u",
731 fwd_chain->to_chain, spadat->use_src_ip,
732 spadat->spa_message_remain, exp_ts
735 fwd_chain->active_rules++;
737 /* Reset the next expected expire time for this chain if it
740 if(fwd_chain->next_expire < now || exp_ts < fwd_chain->next_expire)
741 fwd_chain->next_expire = exp_ts;
744 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
747 if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain))
750 /* Make sure the required jump rule exists
752 if (jump_rule_exists(IPT_DNAT_ACCESS) == 0)
753 add_jump_rule(opts, IPT_DNAT_ACCESS);
757 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_DNAT_RULE_ARGS,
758 opts->fw_config->fw_command,
760 dnat_chain->to_chain,
770 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
773 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
774 cmd_buf, res, err_buf);
776 if(EXTCMD_IS_SUCCESS(res))
778 log_msg(LOG_INFO, "Added DNAT Rule to %s for %s, %s expires at %u",
779 dnat_chain->to_chain, spadat->use_src_ip,
780 spadat->spa_message_remain, exp_ts
783 dnat_chain->active_rules++;
785 /* Reset the next expected expire time for this chain if it
788 if(dnat_chain->next_expire < now || exp_ts < dnat_chain->next_expire)
789 dnat_chain->next_expire = exp_ts;
792 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
795 /* If SNAT (or MASQUERADE) is wanted, then we add those rules here as well.
797 if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1) == 0)
801 /* Setup some parameter depending on whether we are using SNAT
804 if(strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0)
806 /* Using static SNAT */
807 snat_chain = &(opts->fw_config->chain[IPT_SNAT_ACCESS]);
808 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
809 "--to-source %s:%i", opts->config[CONF_SNAT_TRANSLATE_IP],
814 /* Using MASQUERADE */
815 snat_chain = &(opts->fw_config->chain[IPT_MASQUERADE_ACCESS]);
816 snprintf(snat_target, SNAT_TARGET_BUFSIZE-1,
817 "--to-ports %i", fst_port);
820 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_SNAT_RULE_ARGS,
821 opts->fw_config->fw_command,
823 snat_chain->to_chain,
832 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
835 log_msg(LOG_INFO, "process_spa_request() CMD: '%s' (res: %d, err: %s)",
836 cmd_buf, res, err_buf);
838 if(EXTCMD_IS_SUCCESS(res))
840 log_msg(LOG_INFO, "Added Source NAT Rule to %s for %s, %s expires at %u",
841 snat_chain->to_chain, spadat->use_src_ip,
842 spadat->spa_message_remain, exp_ts
845 snat_chain->active_rules++;
847 /* Reset the next expected expire time for this chain if it
850 if(snat_chain->next_expire < now || exp_ts < snat_chain->next_expire)
851 snat_chain->next_expire = exp_ts;
854 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
858 /* Done with the port list for access rules.
860 free_acc_port_list(port_list);
865 /* Iterate over the configure firewall access chains and purge expired
869 check_firewall_rules(const fko_srv_options_t *opts)
872 char rule_num_str[6];
873 char *ndx, *rn_start, *rn_end, *tmp_mark;
875 int i, res, rn_offset;
876 time_t now, rule_exp, min_exp = 0;
878 struct fw_chain *ch = opts->fw_config->chain;
882 /* Iterate over each chain and look for active rules to delete.
884 for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++)
886 /* If there are no active rules or we have not yet
887 * reached our expected next expire time, continue.
889 if(ch[i].active_rules == 0 || ch[i].next_expire > now)
896 /* There should be a rule to delete. Get the current list of
897 * rules for this chain and delete the ones that are expired.
899 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS,
900 opts->fw_config->fw_command,
905 res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0);
908 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
909 cmd_buf, res, err_buf);
911 if(!EXTCMD_IS_SUCCESS(res))
913 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out);
917 if(opts->verbose > 1)
918 log_msg(LOG_INFO, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out);
920 ndx = strstr(cmd_out, EXPIRE_COMMENT_PREFIX);
923 /* we did not find an expected rule.
926 "Did not find expire comment in rules list %i.\n", i);
928 if (ch[i].active_rules > 0)
929 ch[i].active_rules--;
934 /* walk the list and process rules as needed.
936 while (ndx != NULL) {
937 /* Jump forward and extract the timestamp
939 ndx += strlen(EXPIRE_COMMENT_PREFIX);
941 /* remember this spot for when we look for the next
946 strlcpy(exp_str, ndx, 11);
947 rule_exp = (time_t)atoll(exp_str);
951 /* Backtrack and get the rule number and delete it.
954 while(--rn_start > cmd_out)
956 if(*rn_start == '\n')
960 if(*rn_start != '\n')
962 /* This should not happen. But if it does, complain,
963 * decrement the active rule value, and go on.
966 "Rule parse error while finding rule line start in chain %i", i);
968 if (ch[i].active_rules > 0)
969 ch[i].active_rules--;
975 rn_end = strchr(rn_start, ' ');
978 /* This should not happen. But if it does, complain,
979 * decrement the active rule value, and go on.
982 "Rule parse error while finding rule number in chain %i", i);
984 if (ch[i].active_rules > 0)
985 ch[i].active_rules--;
990 strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1);
994 snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS,
995 opts->fw_config->fw_command,
998 atoi(rule_num_str) - rn_offset
1002 res = run_extcmd(cmd_buf, err_buf, CMD_BUFSIZE, 0);
1005 log_msg(LOG_INFO, "check_firewall_rules() CMD: '%s' (res: %d, err: %s)",
1006 cmd_buf, res, err_buf);
1008 if(EXTCMD_IS_SUCCESS(res))
1010 log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u.",
1011 rule_num_str, ch[i].to_chain, rule_exp
1016 if (ch[i].active_rules > 0)
1017 ch[i].active_rules--;
1020 log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf);
1025 /* Track the minimum future rule expire time.
1028 min_exp = (min_exp < rule_exp) ? min_exp : rule_exp;
1031 /* Push our tracking index forward beyond (just processed) _exp_
1032 * string so we can continue to the next rule in the list.
1034 ndx = strstr(tmp_mark, EXPIRE_COMMENT_PREFIX);
1037 /* Set the next pending expire time accordingly. 0 if there are no
1038 * more rules, or whatever the next expected (min_exp) time will be.
1040 if(ch[i].active_rules < 1)
1041 ch[i].next_expire = 0;
1043 ch[i].next_expire = min_exp;
1047 #endif /* FIREWALL_IPTABLES */