From 838b80fd7d7b822cfeecce9f2dc34c6ca49f68cd Mon Sep 17 00:00:00 2001 From: Damien Stuart Date: Tue, 10 Aug 2010 02:29:09 +0000 Subject: [PATCH] Refactored firewall rule code to separate files by firewall type. Stubbed in ipfw and ipf firewall types. Updated autoconf to set a firewall type and path depending on configure arguments. git-svn-id: file:///home/mbr/svn/fwknop/trunk@279 510a4753-2344-4c79-9c09-4d669213fbeb --- common/netinet_common.h | 7 + configure.ac | 76 +++- server/Makefile.am | 4 +- server/config_init.c | 16 +- server/fw_util.c | 895 +------------------------------------- server/fw_util.h | 26 +- server/fw_util_ipf.c | 172 ++++++++ server/fw_util_ipf.h | 43 ++ server/fw_util_ipfw.c | 173 ++++++++ server/fw_util_ipfw.h | 43 ++ server/fw_util_iptables.c | 881 +++++++++++++++++++++++++++++++++++++ server/fw_util_iptables.h | 47 ++ server/fwknopd.c | 6 +- server/fwknopd.conf | 2 +- server/fwknopd_common.h | 6 +- server/pcap_capture.c | 4 +- 16 files changed, 1455 insertions(+), 946 deletions(-) create mode 100644 server/fw_util_ipf.c create mode 100644 server/fw_util_ipf.h create mode 100644 server/fw_util_ipfw.c create mode 100644 server/fw_util_ipfw.h create mode 100644 server/fw_util_iptables.c create mode 100644 server/fw_util_iptables.h diff --git a/common/netinet_common.h b/common/netinet_common.h index bf8f48eb..9dca383e 100644 --- a/common/netinet_common.h +++ b/common/netinet_common.h @@ -44,6 +44,13 @@ #endif #if HAVE_NET_ETHERNET_H #include + #elif HAVE_SYS_ETHERNET_H + #include /* Seems to be where Solaris puts it. */ + /* Also probably need to define ETHER_IS_VALID_LEN here */ + #ifndef ETHER_IS_VALID_LEN + #define ETHER_IS_VALID_LEN(x) \ + ((x) >= ETHERMIN && (x) <= ETHERMAX) + #endif #endif #endif diff --git a/configure.ac b/configure.ac index 0c40805f..a267923b 100644 --- a/configure.ac +++ b/configure.ac @@ -203,21 +203,17 @@ dnl [AS_HELP_STRING([--with-iptables=/path/to/iptables], [Specify path to the iptables executable @<:@default=check path@:>@])], [ - AS_IF([ test "x$withval" = x -o "x$withval" = xyes -o "x$withval" = xno ], + AS_IF([ test "x$withval" = xno ], [], + AS_IF([ test "x$withval" = x -o "x$withval" = xyes ], [AC_MSG_ERROR([--with-iptables requires an argument specifying a path to iptables])], [ IPTABLES_EXE=$withval ] ) + ) ], [ - AC_PATH_PROG(IPTABLES_EXE, [iptables], [], [$APP_PATH]) + AC_PATH_PROG(IPTABLES_EXE, [iptables], [], [$APP_PATH]) ] ) - AS_IF([test "x$IPTABLES_EXE" != x], - [ - AC_DEFINE_UNQUOTED([IPTABLES_EXE], ["$IPTABLES_EXE"], [Path to iptables executable]) - iptables_exe=$IPTABLES_EXE - ], [ iptables_exe="(not found)"] - ) dnl Check for ipfw dnl @@ -225,22 +221,64 @@ dnl [AS_HELP_STRING([--with-ipfw=/path/to/ipfw], [Specify path to the ipfw executable @<:@default=check path@:>@])], [ - AS_IF([ test "x$withval" = x -o "x$withval" = xyes -o "x$withval" = xno ], + AS_IF([ test "x$withval" = xno ], [], + AS_IF([ test "x$withval" = x -o "x$withval" = xyes ], [AC_MSG_ERROR([--with-ipfw requires an argument specifying a path to ipfw])], [ IPFW_EXE=$withval ] ) + ) ], [ - AC_PATH_PROG(IPFW_EXE, [ipfw], [], [$APP_PATH]) + AC_PATH_PROG(IPFW_EXE, [ipfw], [], [$APP_PATH]) ] ) - AS_IF([test "x$IPFW_EXE" != x], - [ - AC_DEFINE_UNQUOTED([IPFW_EXE], ["$IPFW_EXE"], [Path to ipfw executable]) - ipfw_exe=$IPFW_EXE - ], [ ipfw_exe="(not found)"] - )], +dnl Check for ipf (ipfilter) +dnl + AC_ARG_WITH([ipf], + [AS_HELP_STRING([--with-ipf=/path/to/ipf], + [Specify path to the ipf executable @<:@default=check path@:>@])], + [ + AS_IF([ test "x$withval" = xno ], [], + AS_IF([ test "x$withval" = x -o "x$withval" = xyes ], + [AC_MSG_ERROR([--with-ipfw requires an argument specifying a path to ipfw])], + [ IPF_EXE=$withval ] + ) + ) + ], + [ + AC_PATH_PROG(IPF_EXE, [ipf], [], [$APP_PATH]) + ] + ) + +dnl Determine which firewall exe we use (if we have one). +dnl If iptables was found or specified, it wins, then we fallback to ipfw, +dnl otherwise we try ipf. +dnl + AS_IF([test "x$IPTABLES_EXE" != x], [ + FW_DEF="FW_IPTABLES" + FIREWALL_TYPE="iptables" + FIREWALL_EXE=$IPTABLES_EXE + AC_DEFINE_UNQUOTED([FIREWALL_IPTABLES], [1], [The firewall type: iptables.]) + ],[ + AS_IF([test "x$IPFW_EXE" != x], [ + FW_DEF="FW_IPFW" + FIREWALL_TYPE="ipfw" + FIREWALL_EXE=$IPFW_EXE + AC_DEFINE_UNQUOTED([FIREWALL_IPFW], [1], [The firewall type: ipfw.]) + ],[ AS_IF([test "x$IPF_EXE" != x], [ + FIREWALL_TYPE="ipf" + FIREWALL_EXE=$IPF_EXE + AC_DEFINE_UNQUOTED([FIREWALL_IPF], [1], [The firewall type: ipf.]) + ], [AC_MSG_ERROR([No firewall program was found or specified.]) ] + ] + ] + ))) + + AC_DEFINE_UNQUOTED([FIREWALL_EXE], ["$FIREWALL_EXE"], + [Path to firewall command executable (it should match the firewall type).]) + + ], [test "$want_server" = no], [ use_ndbm=no AM_CONDITIONAL([USE_NDBM], [test x$use_ndbm = xno]) @@ -271,9 +309,9 @@ echo " Installation prefix: $prefix " if [test $want_server = "yes" ]; then - echo " Server support programs: - iptables: $iptables_exe - ipfw: $ipfw_exe + echo " Server support: + firewall type: $FIREWALL_TYPE + firewall program path: $FIREWALL_EXE " fi diff --git a/server/Makefile.am b/server/Makefile.am index 7db8dfb7..fa0c252f 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -7,7 +7,9 @@ fwknopd_SOURCES = fwknopd.c fwknopd.h config_init.c config_init.h \ sig_handler.c sig_handler.h replay_dbm.c replay_dbm.h \ access.c access.h fwknopd_errors.c fwknopd_errors.h \ tcp_server.c tcp_server.h extcmd.c extcmd.h \ - fw_util.c fw_util.h + fw_util.c fw_util.h fw_util_ipf.c fw_util_ipf.h \ + fw_util_iptables.c fw_util_iptables.h \ + fw_util_ipfw.c fw_util_ipfw.h fwknopd_LDADD = $(top_builddir)/lib/libfko.la -lpcap if USE_NDBM diff --git a/server/config_init.c b/server/config_init.c index 79ba887b..b240416c 100644 --- a/server/config_init.c +++ b/server/config_init.c @@ -416,11 +416,10 @@ validate_options(fko_srv_options_t *opts) exit(EXIT_FAILURE); } - if(opts->config[CONF_EXE_IPTABLES] == NULL - && opts->config[CONF_EXE_IPFW] == NULL) + if(opts->config[CONF_FIREWALL_EXE] == NULL) { fprintf(stderr, - "No firewall command executable is set. Please check fwknopd.conf for EXE_IPTABLES or EXE_IPFW.\n" + "No firewall command executable is set. Please check FIREWALL_EXE in fwknopd.conf.\n" ); exit(EXIT_FAILURE); } @@ -435,13 +434,12 @@ set_preconfig_entries(fko_srv_options_t *opts) * end up being overwritten via config file or command-line. */ - /* Setup the local executables based on build-time info. + /* Setup the firewall executable based on build-time info. + * --DSS Note: We will want to either force external script mode, or + * error out if we do not have a firewall executable defined. */ -#ifdef IPTABLES_EXE - set_config_entry(opts, CONF_EXE_IPTABLES, IPTABLES_EXE); -#endif -#ifdef IPFW_EXE - set_config_entry(opts, CONF_EXE_IPFW, IPFW_EXE); +#ifdef FIREWALL_EXE + set_config_entry(opts, CONF_FIREWALL_EXE, FIREWALL_EXE); #endif } diff --git a/server/fw_util.c b/server/fw_util.c index ddde1e72..03f08e8f 100644 --- a/server/fw_util.c +++ b/server/fw_util.c @@ -31,899 +31,8 @@ #include "extcmd.h" #include "access.h" -#if HAVE_TIME_H - #include -#endif - -static struct fw_config fwc; - -/* -static void -parse_extcmd_error(int retval, int status, char *se_buf) -{ - char errmsg[CMD_BUFSIZE]; - char *emptr = errmsg; - - if(retval < 0) - { - log_msg(LOG_ERR, "Extcmd fork error: %s", strerror(errno)); - return; - } - - sprintf(emptr, "Extcmd return: %i, command exit status: %i", retval, status); - emptr += strlen(emptr); - - if(EXTCMD_EXECUTION_ERROR(retval)) - { - sprintf(errmsg, "Extcmd stderr=%s", se_buf); - emptr += strlen(emptr); - } - - if(EXTCMD_IS_SUCCESS_PARTIAL_STDOUT(retval)) - { - sprintf(errmsg, "\n - Got partial stdout"); - emptr += strlen(emptr); - } - - if(EXTCMD_IS_SUCCESS_PARTIAL_STDERR(retval)) - { - sprintf(errmsg, "\n - Got partial stderr"); - emptr += strlen(emptr); - } - - if(EXTCMD_STDOUT_READ_ERROR(retval)) - { - sprintf(errmsg, "\n - Got read error on stdout"); - emptr += strlen(emptr); - } - - if(EXTCMD_STDERR_READ_ERROR(retval)) - { - sprintf(errmsg, "\n - Got read error on stderr"); - emptr += strlen(emptr); - } - - log_msg(LOG_WARNING, errmsg); -} +/* --DSS This is a place holder for now. We may put the generalized external + * firewall script code here ( or not). */ -static int -jump_rule_exists(int chain_num) -{ - int num, pos = 0; - char cmd_buf[CMD_BUFSIZE] = {0}; - char target[CMD_BUFSIZE] = {0}; - char line_buf[CMD_BUFSIZE] = {0}; - FILE *ipt; - - sprintf(cmd_buf, "%s " IPT_LIST_RULES_ARGS, - fwc.fw_command, - fwc.chain[chain_num].table, - fwc.chain[chain_num].from_chain - ); - - ipt = popen(cmd_buf, "r"); - - if(ipt == NULL) - { - log_msg(LOG_ERR, - "Got error %i trying to get rules list.\n", errno); - return(-1); - } - - while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL) - { - /* Get past comments and empty lines (note: we only look at the - * first character). - */ - if(IS_EMPTY_LINE(line_buf[0])) - continue; - - if(sscanf(line_buf, "%i %s ", &num, target) == 2) - { - if(strcmp(target, fwc.chain[chain_num].to_chain) == 0) - { - pos = num; - break; - } - } - } - - pclose(ipt); - - return(pos); -} - -/* Print all firewall rules currently instantiated by the running fwknopd - * daemon to stdout. -*/ -int -fw_dump_rules(fko_srv_options_t *opts) -{ - int i; - int res, got_err = 0; - char cmd_buf[CMD_BUFSIZE] = {0}; - char err[CMD_BUFSIZE] = {0}; - - struct fw_chain *ch = opts->fw_config->chain; - - printf("Listing rules in fwknop chains...\n"); - for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) - { - - if(fwc.chain[i].target[0] == '\0') - continue; - - /* Create the list command - */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, - opts->fw_config->fw_command, - ch[i].table, - ch[i].to_chain - ); - - //printf("(%i) CMD: '%s'\n", i, cmd_buf); - res = system(cmd_buf); - - /* Expect full success on this */ - if(! EXTCMD_IS_SUCCESS(res)) - { - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); - got_err++; - } - } - - return(got_err); -} - -/* Quietly flush and delete all fwknop custom chains. -*/ -static void -delete_all_chains(void) -{ - int i, res; - int jump_rule_num; - char cmd_buf[CMD_BUFSIZE] = {0}; - char err[CMD_BUFSIZE] = {0}; - - for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) - { - if(fwc.chain[i].target[0] == '\0') - continue; - - /* First look for a jump rule to this chain and remove it if it - * is there. - */ - if((jump_rule_num = jump_rule_exists(i)) > 0) - { - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, - fwc.fw_command, - fwc.chain[i].table, - fwc.chain[i].from_chain, - jump_rule_num - ); - - //printf("CMD: '%s'\n", cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - /* Expect full success on this */ - if(! EXTCMD_IS_SUCCESS(res)) - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); - } - - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - /* Now flush and remove the chain. - */ - snprintf(cmd_buf, CMD_BUFSIZE-1, - "(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1", - fwc.fw_command, - fwc.chain[i].table, - fwc.chain[i].to_chain, - fwc.fw_command, - fwc.chain[i].table, - fwc.chain[i].to_chain - ); - - //printf("CMD: '%s'\n", cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - /* Expect full success on this */ - if(! EXTCMD_IS_SUCCESS(res)) - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); - } -} - -/* Create the fwknop custom chains (at least those that are configured). -*/ -static int -create_fw_chains(void) -{ - int i; - int res, got_err = 0; - char cmd_buf[CMD_BUFSIZE] = {0}; - char err[CMD_BUFSIZE] = {0}; - - for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) - { - if(fwc.chain[i].target[0] == '\0') - continue; - - /* Create the custom chain. - */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, - fwc.fw_command, - fwc.chain[i].table, - fwc.chain[i].to_chain - ); - - //printf("(%i) CMD: '%s'\n", i, cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - - /* Expect full success on this */ - if(! EXTCMD_IS_SUCCESS(res)) - { - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); - got_err++; - } - - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - /* Then create the jump rule to that chain. - */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, - fwc.fw_command, - fwc.chain[i].table, - fwc.chain[i].from_chain, - fwc.chain[i].jump_rule_pos, - fwc.chain[i].to_chain - ); - - //printf("(%i) CMD: '%s'\n", i, cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - - /* Expect full success on this */ - if(! EXTCMD_IS_SUCCESS(res)) - { - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); - got_err++; - } - } - - return(got_err); -} - - -static void -set_fw_chain_conf(int type, char *conf_str) -{ - int i, j; - char tbuf[1024] = {0}; - char *ndx = conf_str; - - char *chain_fields[FW_NUM_CHAIN_FIELDS]; - - struct fw_chain *chain = &(fwc.chain[type]); - - chain->type = type; - - if(ndx != NULL) - chain_fields[0] = tbuf; - - i = 0; - j = 1; - while(*ndx != '\0') - { - if(*ndx != ' ') - { - if(*ndx == ',') - { - tbuf[i] = '\0'; - chain_fields[j++] = &(tbuf[++i]); - } - else - tbuf[i++] = *ndx; - } - ndx++; - } - - /* Sanity check - j should be the number of chain fields - * (excluding the type). - */ - if(j != FW_NUM_CHAIN_FIELDS) - { - fprintf(stderr, "[*] Custom Chain config parse error.\n" - "Wrong number of fields for chain type %i\n" - "Line: %s\n", type, conf_str); - exit(EXIT_FAILURE); - } - - /* Pull and set Target */ - strlcpy(chain->target, chain_fields[0], MAX_TARGET_NAME_LEN); - - /* Pull and set Direction - if(strcmp(chain_fields[1], FW_CHAIN_DIR_SRC_STR) == 0) - chain->direction = FW_CHAIN_DIR_SRC; - else if(strcmp(chain_fields[1], FW_CHAIN_DIR_DST_STR) == 0) - chain->direction = FW_CHAIN_DIR_DST; - else if(strcmp(chain_fields[1], FW_CHAIN_DIR_BOTH_STR) == 0) - chain->direction = FW_CHAIN_DIR_BOTH; - else - chain->direction = FW_CHAIN_DIR_UNKNOWN; -*/ - /* Pull and set Table */ - strlcpy(chain->table, chain_fields[1], MAX_TABLE_NAME_LEN); - - /* Pull and set From_chain */ - strlcpy(chain->from_chain, chain_fields[2], MAX_CHAIN_NAME_LEN); - - /* Pull and set Jump_rule_position */ - chain->jump_rule_pos = atoi(chain_fields[3]); - - /* Pull and set To_chain */ - strlcpy(chain->to_chain, chain_fields[4], MAX_CHAIN_NAME_LEN); - - /* Pull and set Jump_rule_position */ - chain->rule_pos = atoi(chain_fields[5]); - -} - -void -fw_config_init(fko_srv_options_t *opts) -{ - - memset(&fwc, 0x0, sizeof(struct fw_config)); - - /* Set our firewall exe command path (iptables in most cases). - */ - strlcpy(fwc.fw_command, opts->config[CONF_EXE_IPTABLES], MAX_PATH_LEN); - - /* Pull the fwknop chain config info and setup our internal - * config struct. The IPT_INPUT is the only one that is - * required. The rest are optional. - */ - set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]); - - /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y - */ - if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0) - set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]); - - /* The remaining access chains require ENABLE_IPT_FORWARDING = Y - */ - if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0) - { - - set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]); - set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]); - - /* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y - */ - if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0) - { - /* If an SNAT_TRANSLATE_IP is specified use the SNAT_ACCESS mode. - * Otherwise, use MASQUERADE_ACCESS. - * - * XXX: --DSS: Not sure if using the TRANSLATE_IP parameter as - * the determining factor is the best why to handle - * this. - * - */ - if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL - && strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0) - set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]); - else - set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]); - } - } - - /* Let us find it via our opts struct as well. - */ - opts->fw_config = &fwc; - - return; -} - -void -fw_initialize(void) -{ - int res; - - /* Flush the chains (just in case) so we can start fresh. - */ - delete_all_chains(); - - /* Now create any configured chains. - */ - res = create_fw_chains(); - - if(res != 0) - { - fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n"); - exit(EXIT_FAILURE); - } -} - -void -fw_cleanup(void) -{ - delete_all_chains(); -} - -/****************************************************************************/ - -/* Rule Processing - Create an access request... -*/ -int -process_spa_request(fko_srv_options_t *opts, spa_data_t *spadat) -{ - char cmd_buf[CMD_BUFSIZE] = {0}; - char err[CMD_BUFSIZE] = {0}; - char nat_ip[16] = {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. - */ - 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) - { - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - 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 - ); - -//--DSS tmp -//fprintf(stderr, "ADD CMD: %s\n", cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - 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); - - /* 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)) - { - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - 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 - ); - -//--DSS tmp -//fprintf(stderr, "ADD OUTPUT CMD: %s\n", cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - 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); - - } - - ple = ple->next; - } - - /* Done with the port list for access rules. - */ - free_acc_port_list(port_list); - - } - /* 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 ) - { - /* Parse out the NAT IP and Port components. - */ - ndx = strchr(spadat->nat_access, ','); - if(ndx != NULL) - { - strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1); - nat_port = atoi(ndx+1); - } - -// --DSS temp -//fprintf(stderr, "NAT IP: '%s', NAT PORT: '%i'\n", nat_ip, nat_port); - - /* Make our FORWARD and NAT rules - */ - if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain)) - { - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - 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 - ); - -//--DSS tmp -//fprintf(stderr, "ADD OUTPUT CMD: %s\n", cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - 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); - } - - if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain)) - { - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - 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 - ); - -//--DSS tmp -//fprintf(stderr, "ADD DNAT CMD: %s\n", cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - 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); - } - - /* 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) - { - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - /* 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, CMD_BUFSIZE, 0); - 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); - } - } - - return(res); -} - -/* Iterate over the configure firewall access chains and purge expired - * firewall rules. -*/ -void -check_firewall_rules(fko_srv_options_t *opts) -{ - char cmd_buf[CMD_BUFSIZE] = {0}; - char err[CMD_BUFSIZE] = {0}; - char cmd_out[STANDARD_CMD_OUT_BUFSIZE]; - char exp_str[12]; - char rule_num_str[6]; - char *ndx, *rn_start, *rn_end, *tmp_mark; - - int i, res, rn_offset; - time_t now, rule_exp, min_exp = 0; - - struct fw_chain *ch = opts->fw_config->chain; - - time(&now); - - /* Iterate over each chain and look for active rules to delete. - */ - for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++) - { - /* Just in case we somehow lose track and fall out-of-whack, - * we be the hero and reset it to zero. - * (poet but don't know it :-o ) - */ - if(ch[i].active_rules < 0) - ch[i].active_rules = 0; - - /* If there are no active rules or we have not yet - * reached our expected next expire time, continue. - */ - if(ch[i].active_rules == 0 || ch[i].next_expire > now) - continue; - - rn_offset = 0; - - /* There should be a rule to delete. Get the current list of - * rules for this chain and delete the ones that are expired. - */ - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, - opts->fw_config->fw_command, - ch[i].table, - ch[i].to_chain - ); - - memset(cmd_out, 0x0, STANDARD_CMD_OUT_BUFSIZE); - - res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0); - - if(!EXTCMD_IS_SUCCESS(res)) - { - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out); - continue; - } - - if(opts->verbose > 2) - log_msg(LOG_INFO, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out); - - ndx = strstr(cmd_out, "_exp_"); - if(ndx == NULL) - { - /* we did not find an expected rule. - */ - log_msg(LOG_ERR, - "Did not find expire comment in rules list %i.\n", i); - - ch[i].active_rules--; - continue; - } - - /* walk the list and process rules as needed. - */ - while (ndx != NULL) { - /* Jump forward and extract the timestamp - */ - ndx +=5; - - /* remember this spot for when we look for the next - * rule. - */ - tmp_mark = ndx; - - strlcpy(exp_str, ndx, 11); - rule_exp = (time_t)atoll(exp_str); - -//fprintf(stderr, "RULE_EXP=%u, NOW=%u\n", rule_exp, now); - if(rule_exp <= now) - { - /* Backtrack and get the rule number and delete it. - */ - rn_start = ndx; - while(--rn_start > cmd_out) - { - if(*rn_start == '\n') - break; - } - - if(*rn_start != '\n') - { - /* This should not happen. But if it does, complain, - * decrement the active rule value, and go on. - */ - log_msg(LOG_ERR, - "Rule parse error while finding rule line start in chain %i", i); - - ch[i].active_rules--; - break; - } - rn_start++; - - rn_end = strchr(rn_start, ' '); - if(rn_end == NULL) - { - /* This should not happen. But if it does, complain, - * decrement the active rule value, and go on. - */ - log_msg(LOG_ERR, - "Rule parse error while finding rule number in chain %i", i); - - ch[i].active_rules--; - break; - } - - strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1); - - memset(cmd_buf, 0x0, CMD_BUFSIZE); - - snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, - opts->fw_config->fw_command, - ch[i].table, - ch[i].to_chain, - atoi(rule_num_str) - rn_offset - ); - - -//fprintf(stderr, "DELETE RULE CMD: %s\n", cmd_buf); - res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); - if(EXTCMD_IS_SUCCESS(res)) - { - log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u.", - rule_num_str, ch[i].to_chain, rule_exp - ); - - rn_offset++; - ch[i].active_rules--; - } - else - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); - - } - else - { - /* Track the minimum future rule expire time. - */ - if(rule_exp > now) - min_exp = (min_exp < rule_exp) ? min_exp : rule_exp; - } - - /* Push our tracking index forward beyond (just processed) _exp_ - * string so we can continue to the next rule in the list. - */ - ndx = strstr(tmp_mark, "_exp_"); - } - - /* Set the next pending expire time accordingly. 0 if there are no - * more rules, or whatever the next expected (min_exp) time will be. - */ - if(ch[i].active_rules < 1) - ch[i].next_expire = 0; - else if(min_exp) - ch[i].next_expire = min_exp; - } -} - /***EOF***/ diff --git a/server/fw_util.h b/server/fw_util.h index b0427f80..837cf667 100644 --- a/server/fw_util.h +++ b/server/fw_util.h @@ -31,30 +31,26 @@ #define STANDARD_CMD_OUT_BUFSIZE 4096 -#define SNAT_TARGET_BUFSIZE 64 +#if FIREWALL_IPTABLES + #include "fw_util_iptables.h" +#elif FIREWALL_IPFW + #include "fw_util_ipfw.h" +#elif FIREWALL_IPF + #include "fw_util_ipf.h" +#endif -/* iptables command args -*/ -#define IPT_ADD_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -m comment --comment _exp_%u -j %s 2>&1" -#define IPT_ADD_OUT_RULE_ARGS "-t %s -A %s -p %i -d %s --sport %i -m comment --comment _exp_%u -j %s 2>&1" -#define IPT_ADD_FWD_RULE_ARGS "-t %s -A %s -p %i -s %s -d %s --dport %i -m comment --comment _exp_%u -j %s 2>&1" -#define IPT_ADD_DNAT_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -m comment --comment _exp_%u -j %s --to-destination %s:%i 2>&1" -#define IPT_ADD_SNAT_RULE_ARGS "-t %s -A %s -p %i -d %s --dport %i -m comment --comment _exp_%u -j %s %s 2>&1" -#define IPT_DEL_RULE_ARGS "-t %s -D %s %i 2>&1" -#define IPT_NEW_CHAIN_ARGS "-t %s -N %s 2>&1" -#define IPT_FLUSH_CHAIN_ARGS "-t %s -F %s 2>&1" -#define IPT_DEL_CHAIN_ARGS "-t %s -X %s 2>&1" -#define IPT_ADD_JUMP_RULE_ARGS "-t %s -I %s %i -j %s 2>&1" -#define IPT_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n 2>&1" +#if HAVE_TIME_H + #include +#endif /* Function prototypes */ void fw_config_init(fko_srv_options_t *opts); void fw_initialize(void); void fw_cleanup(void); -int process_spa_request(fko_srv_options_t *opts, spa_data_t *spdat); void check_firewall_rules(fko_srv_options_t *opts); int fw_dump_rules(fko_srv_options_t *opts); +int process_spa_request(fko_srv_options_t *opts, spa_data_t *spdat); #endif /* FW_UTIL_H */ diff --git a/server/fw_util_ipf.c b/server/fw_util_ipf.c new file mode 100644 index 00000000..bea101e2 --- /dev/null +++ b/server/fw_util_ipf.c @@ -0,0 +1,172 @@ +/* $Id$ + ***************************************************************************** + * + * File: fw_util_ipf.c + * + * Author: Damien S. Stuart + * + * Purpose: Fwknop routines for managing ipf firewall rules. + * + * Copyright (C) 2010 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#include "fwknopd_common.h" + +#if FIREWALL_IPF + +#include "fw_util.h" +#include "utils.h" +#include "log_msg.h" +#include "config_init.h" /* for the IS_EMPTY_LINE macro */ +#include "extcmd.h" +#include "access.h" + +static struct fw_config fwc; + +/* Print all firewall rules currently instantiated by the running fwknopd + * daemon to stdout. +*/ +int +fw_dump_rules(fko_srv_options_t *opts) +{ + int i; + int res, got_err = 0; + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + + /* TODO: Implement or get rid of me */ + + return(got_err); +} + +void +fw_config_init(fko_srv_options_t *opts) +{ + /* TODO: Implement me */ + + memset(&fwc, 0x0, sizeof(struct fw_config)); + + /* Set our firewall exe command path (iptables in most cases). + */ + strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], MAX_PATH_LEN); + + + /* Let us find it via our opts struct as well. + */ + opts->fw_config = &fwc; + + return; +} + +void +fw_initialize(void) +{ + int res = 0; + + /* TODO: Implement me */ + + if(res != 0) + { + fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n"); + exit(EXIT_FAILURE); + } +} + +void +fw_cleanup(void) +{ + + /* TODO: Implement or get rid of me */ + +} + +/****************************************************************************/ + +/* Rule Processing - Create an access request... +*/ +int +process_spa_request(fko_srv_options_t *opts, spa_data_t *spadat) +{ + /* TODO: Implement me */ + + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + char nat_ip[16] = {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; + + 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; + + /* TODO: Implement me */ + + return(res); +} + +/* Iterate over the configure firewall access chains and purge expired + * firewall rules. +*/ +void +check_firewall_rules(fko_srv_options_t *opts) +{ + + /* TODO: Implement me */ + + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + char cmd_out[STANDARD_CMD_OUT_BUFSIZE]; + char exp_str[12]; + char rule_num_str[6]; + char *ndx, *rn_start, *rn_end, *tmp_mark; + + int i, res, rn_offset; + time_t now, rule_exp, min_exp = 0; + + time(&now); + +} + +#endif /* FIREWALL_IPF */ + +/***EOF***/ diff --git a/server/fw_util_ipf.h b/server/fw_util_ipf.h new file mode 100644 index 00000000..0d5e324c --- /dev/null +++ b/server/fw_util_ipf.h @@ -0,0 +1,43 @@ +/* $Id$ + ***************************************************************************** + * + * File: fw_util_ipf.h + * + * Author: Damien Stuart (dstuart@dstuart.org) + * + * Purpose: Header file for fw_util_ipf.c. + * + * Copyright (C) 2010 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#ifndef FW_UTIL_IPF_H +#define FW_UTIL_IPF_H + +#define SNAT_TARGET_BUFSIZE 64 + +/* ipfw command args (gotta flesh these out) +*/ +#define IPF_ADD_RULE_ARGS "" +#define IPF_ADD_OUT_RULE_ARGS "" +#define IPF_ADD_FWD_RULE_ARGS "" +#define IPF_ADD_DNAT_RULE_ARGS "" +#define IPF_ADD_SNAT_RULE_ARGS "" +#define IPF_DEL_RULE_ARGS "" +#define IPF_LIST_RULES_ARGS "" + +#endif /* FW_UTIL_IPF_H */ + +/***EOF***/ diff --git a/server/fw_util_ipfw.c b/server/fw_util_ipfw.c new file mode 100644 index 00000000..935cc9f2 --- /dev/null +++ b/server/fw_util_ipfw.c @@ -0,0 +1,173 @@ +/* $Id$ + ***************************************************************************** + * + * File: fw_util_ipfw.c + * + * Author: Damien S. Stuart + * + * Purpose: Fwknop routines for managing ipfw firewall rules. + * + * Copyright (C) 2010 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#include "fwknopd_common.h" + +#if FIREWALL_IPFW + +#include "fw_util.h" +#include "utils.h" +#include "log_msg.h" +#include "config_init.h" /* for the IS_EMPTY_LINE macro */ +#include "extcmd.h" +#include "access.h" + +static struct fw_config fwc; + +/* Print all firewall rules currently instantiated by the running fwknopd + * daemon to stdout. +*/ +int +fw_dump_rules(fko_srv_options_t *opts) +{ + int i; + int res, got_err = 0; + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + + /* TODO: Implement me */ + + return(got_err); +} + +void +fw_config_init(fko_srv_options_t *opts) +{ + + + /* TODO: Implement me */ + + memset(&fwc, 0x0, sizeof(struct fw_config)); + + /* Set our firewall exe command path (iptables in most cases). + */ + strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], MAX_PATH_LEN); + + + /* Let us find it via our opts struct as well. + */ + opts->fw_config = &fwc; + + return; +} + +void +fw_initialize(void) +{ + int res = 0; + + /* TODO: Implement me */ + + if(res != 0) + { + fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n"); + exit(EXIT_FAILURE); + } +} + +void +fw_cleanup(void) +{ + + /* TODO: Implement me */ + +} + +/****************************************************************************/ + +/* Rule Processing - Create an access request... +*/ +int +process_spa_request(fko_srv_options_t *opts, spa_data_t *spadat) +{ + /* TODO: Implement me */ + + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + char nat_ip[16] = {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; + + 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; + + /* TODO: Implement me */ + + return(res); +} + +/* Iterate over the configure firewall access chains and purge expired + * firewall rules. +*/ +void +check_firewall_rules(fko_srv_options_t *opts) +{ + /* TODO: Implement me */ + + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + char cmd_out[STANDARD_CMD_OUT_BUFSIZE]; + char exp_str[12]; + char rule_num_str[6]; + char *ndx, *rn_start, *rn_end, *tmp_mark; + + int i, res, rn_offset; + time_t now, rule_exp, min_exp = 0; + + time(&now); + +} + +#endif /* FIREWALL_IPFW */ + +/***EOF***/ diff --git a/server/fw_util_ipfw.h b/server/fw_util_ipfw.h new file mode 100644 index 00000000..210cb68b --- /dev/null +++ b/server/fw_util_ipfw.h @@ -0,0 +1,43 @@ +/* $Id$ + ***************************************************************************** + * + * File: fw_util_ipfw.h + * + * Author: Damien Stuart (dstuart@dstuart.org) + * + * Purpose: Header file for fw_util_ipfw.c. + * + * Copyright (C) 2010 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#ifndef FW_UTIL_IPFW_H +#define FW_UTIL_IPFW_H + +#define SNAT_TARGET_BUFSIZE 64 + +/* ipfw command args (gotta flesh these out) +*/ +#define IPFW_ADD_RULE_ARGS "" +#define IPFW_ADD_OUT_RULE_ARGS "" +#define IPFW_ADD_FWD_RULE_ARGS "" +#define IPFW_ADD_DNAT_RULE_ARGS "" +#define IPFW_ADD_SNAT_RULE_ARGS "" +#define IPFW_DEL_RULE_ARGS "" +#define IPFW_LIST_RULES_ARGS "" + +#endif /* FW_UTIL_IPFW_H */ + +/***EOF***/ diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c new file mode 100644 index 00000000..86beec1a --- /dev/null +++ b/server/fw_util_iptables.c @@ -0,0 +1,881 @@ +/* $Id$ + ***************************************************************************** + * + * File: fw_util_iptables.c + * + * Author: Damien S. Stuart + * + * Purpose: Fwknop routines for managing iptables firewall rules. + * + * Copyright (C) 2010 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ + +#include "fwknopd_common.h" + +#ifdef FIREWALL_IPTABLES + +#include "fw_util.h" +#include "utils.h" +#include "log_msg.h" +#include "config_init.h" /* for the IS_EMPTY_LINE macro */ +#include "extcmd.h" +#include "access.h" + +static struct fw_config fwc; + +static int +jump_rule_exists(int chain_num) +{ + int num, pos = 0; + char cmd_buf[CMD_BUFSIZE] = {0}; + char target[CMD_BUFSIZE] = {0}; + char line_buf[CMD_BUFSIZE] = {0}; + FILE *ipt; + + sprintf(cmd_buf, "%s " IPT_LIST_RULES_ARGS, + fwc.fw_command, + fwc.chain[chain_num].table, + fwc.chain[chain_num].from_chain + ); + + ipt = popen(cmd_buf, "r"); + + if(ipt == NULL) + { + log_msg(LOG_ERR, + "Got error %i trying to get rules list.\n", errno); + return(-1); + } + + while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL) + { + /* Get past comments and empty lines (note: we only look at the + * first character). + */ + if(IS_EMPTY_LINE(line_buf[0])) + continue; + + if(sscanf(line_buf, "%i %s ", &num, target) == 2) + { + if(strcmp(target, fwc.chain[chain_num].to_chain) == 0) + { + pos = num; + break; + } + } + } + + pclose(ipt); + + return(pos); +} + +/* Print all firewall rules currently instantiated by the running fwknopd + * daemon to stdout. +*/ +int +fw_dump_rules(fko_srv_options_t *opts) +{ + int i; + int res, got_err = 0; + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + + struct fw_chain *ch = opts->fw_config->chain; + + printf("Listing rules in fwknop chains...\n"); + for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) + { + + if(fwc.chain[i].target[0] == '\0') + continue; + + /* Create the list command + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + opts->fw_config->fw_command, + ch[i].table, + ch[i].to_chain + ); + + //printf("(%i) CMD: '%s'\n", i, cmd_buf); + res = system(cmd_buf); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); + got_err++; + } + } + + return(got_err); +} + +/* Quietly flush and delete all fwknop custom chains. +*/ +static void +delete_all_chains(void) +{ + int i, res; + int jump_rule_num; + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + + for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) + { + if(fwc.chain[i].target[0] == '\0') + continue; + + /* First look for a jump rule to this chain and remove it if it + * is there. + */ + if((jump_rule_num = jump_rule_exists(i)) > 0) + { + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].from_chain, + jump_rule_num + ); + + //printf("CMD: '%s'\n", cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); + } + + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + /* Now flush and remove the chain. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, + "(%s " IPT_FLUSH_CHAIN_ARGS "; %s " IPT_DEL_CHAIN_ARGS ")", // > /dev/null 2>&1", + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].to_chain, + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].to_chain + ); + + //printf("CMD: '%s'\n", cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); + } +} + +/* Create the fwknop custom chains (at least those that are configured). +*/ +static int +create_fw_chains(void) +{ + int i; + int res, got_err = 0; + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + + for(i=0; i<(NUM_FWKNOP_ACCESS_TYPES); i++) + { + if(fwc.chain[i].target[0] == '\0') + continue; + + /* Create the custom chain. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].to_chain + ); + + //printf("(%i) CMD: '%s'\n", i, cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); + got_err++; + } + + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + /* Then create the jump rule to that chain. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, + fwc.fw_command, + fwc.chain[i].table, + fwc.chain[i].from_chain, + fwc.chain[i].jump_rule_pos, + fwc.chain[i].to_chain + ); + + //printf("(%i) CMD: '%s'\n", i, cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + + /* Expect full success on this */ + if(! EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); + got_err++; + } + } + + return(got_err); +} + + +static void +set_fw_chain_conf(int type, char *conf_str) +{ + int i, j; + char tbuf[1024] = {0}; + char *ndx = conf_str; + + char *chain_fields[FW_NUM_CHAIN_FIELDS]; + + struct fw_chain *chain = &(fwc.chain[type]); + + chain->type = type; + + if(ndx != NULL) + chain_fields[0] = tbuf; + + i = 0; + j = 1; + while(*ndx != '\0') + { + if(*ndx != ' ') + { + if(*ndx == ',') + { + tbuf[i] = '\0'; + chain_fields[j++] = &(tbuf[++i]); + } + else + tbuf[i++] = *ndx; + } + ndx++; + } + + /* Sanity check - j should be the number of chain fields + * (excluding the type). + */ + if(j != FW_NUM_CHAIN_FIELDS) + { + fprintf(stderr, "[*] Custom Chain config parse error.\n" + "Wrong number of fields for chain type %i\n" + "Line: %s\n", type, conf_str); + exit(EXIT_FAILURE); + } + + /* Pull and set Target */ + strlcpy(chain->target, chain_fields[0], MAX_TARGET_NAME_LEN); + + /* Pull and set Direction + if(strcmp(chain_fields[1], FW_CHAIN_DIR_SRC_STR) == 0) + chain->direction = FW_CHAIN_DIR_SRC; + else if(strcmp(chain_fields[1], FW_CHAIN_DIR_DST_STR) == 0) + chain->direction = FW_CHAIN_DIR_DST; + else if(strcmp(chain_fields[1], FW_CHAIN_DIR_BOTH_STR) == 0) + chain->direction = FW_CHAIN_DIR_BOTH; + else + chain->direction = FW_CHAIN_DIR_UNKNOWN; +*/ + /* Pull and set Table */ + strlcpy(chain->table, chain_fields[1], MAX_TABLE_NAME_LEN); + + /* Pull and set From_chain */ + strlcpy(chain->from_chain, chain_fields[2], MAX_CHAIN_NAME_LEN); + + /* Pull and set Jump_rule_position */ + chain->jump_rule_pos = atoi(chain_fields[3]); + + /* Pull and set To_chain */ + strlcpy(chain->to_chain, chain_fields[4], MAX_CHAIN_NAME_LEN); + + /* Pull and set Jump_rule_position */ + chain->rule_pos = atoi(chain_fields[5]); + +} + +void +fw_config_init(fko_srv_options_t *opts) +{ + + memset(&fwc, 0x0, sizeof(struct fw_config)); + + /* Set our firewall exe command path (iptables in most cases). + */ + strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], MAX_PATH_LEN); + + /* Pull the fwknop chain config info and setup our internal + * config struct. The IPT_INPUT is the only one that is + * required. The rest are optional. + */ + set_fw_chain_conf(IPT_INPUT_ACCESS, opts->config[CONF_IPT_INPUT_ACCESS]); + + /* The FWKNOP_OUTPUT_ACCESS requires ENABLE_IPT_OUTPUT_ACCESS be Y + */ + if(strncasecmp(opts->config[CONF_ENABLE_IPT_OUTPUT], "Y", 1)==0) + set_fw_chain_conf(IPT_OUTPUT_ACCESS, opts->config[CONF_IPT_OUTPUT_ACCESS]); + + /* The remaining access chains require ENABLE_IPT_FORWARDING = Y + */ + if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1)==0) + { + + set_fw_chain_conf(IPT_FORWARD_ACCESS, opts->config[CONF_IPT_FORWARD_ACCESS]); + set_fw_chain_conf(IPT_DNAT_ACCESS, opts->config[CONF_IPT_DNAT_ACCESS]); + + /* SNAT (whichever mode) requires ENABLE_IPT_SNAT = Y + */ + if(strncasecmp(opts->config[CONF_ENABLE_IPT_SNAT], "Y", 1)==0) + { + /* If an SNAT_TRANSLATE_IP is specified use the SNAT_ACCESS mode. + * Otherwise, use MASQUERADE_ACCESS. + * + * XXX: --DSS: Not sure if using the TRANSLATE_IP parameter as + * the determining factor is the best why to handle + * this. + * + */ + if(opts->config[CONF_SNAT_TRANSLATE_IP] != NULL + && strncasecmp(opts->config[CONF_SNAT_TRANSLATE_IP], "__CHANGEME__", 10)!=0) + set_fw_chain_conf(IPT_SNAT_ACCESS, opts->config[CONF_IPT_SNAT_ACCESS]); + else + set_fw_chain_conf(IPT_MASQUERADE_ACCESS, opts->config[CONF_IPT_MASQUERADE_ACCESS]); + } + } + + /* Let us find it via our opts struct as well. + */ + opts->fw_config = &fwc; + + return; +} + +void +fw_initialize(void) +{ + int res; + + /* Flush the chains (just in case) so we can start fresh. + */ + delete_all_chains(); + + /* Now create any configured chains. + */ + res = create_fw_chains(); + + if(res != 0) + { + fprintf(stderr, "Warning: Errors detected during fwknop custom chain creation.\n"); + exit(EXIT_FAILURE); + } +} + +void +fw_cleanup(void) +{ + delete_all_chains(); +} + +/****************************************************************************/ + +/* Rule Processing - Create an access request... +*/ +int +process_spa_request(fko_srv_options_t *opts, spa_data_t *spadat) +{ + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + char nat_ip[16] = {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. + */ + 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) + { + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + 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 + ); + +//--DSS tmp +//fprintf(stderr, "ADD CMD: %s\n", cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + 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); + + /* 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)) + { + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + 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 + ); + +//--DSS tmp +//fprintf(stderr, "ADD OUTPUT CMD: %s\n", cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + 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); + + } + + ple = ple->next; + } + + /* Done with the port list for access rules. + */ + free_acc_port_list(port_list); + + } + /* 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 ) + { + /* Parse out the NAT IP and Port components. + */ + ndx = strchr(spadat->nat_access, ','); + if(ndx != NULL) + { + strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1); + nat_port = atoi(ndx+1); + } + +// --DSS temp +//fprintf(stderr, "NAT IP: '%s', NAT PORT: '%i'\n", nat_ip, nat_port); + + /* Make our FORWARD and NAT rules + */ + if(fwd_chain->to_chain != NULL && strlen(fwd_chain->to_chain)) + { + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + 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 + ); + +//--DSS tmp +//fprintf(stderr, "ADD OUTPUT CMD: %s\n", cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + 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); + } + + if(dnat_chain->to_chain != NULL && strlen(dnat_chain->to_chain)) + { + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + 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 + ); + +//--DSS tmp +//fprintf(stderr, "ADD DNAT CMD: %s\n", cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + 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); + } + + /* 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) + { + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + /* 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, CMD_BUFSIZE, 0); + 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); + } + } + + return(res); +} + +/* Iterate over the configure firewall access chains and purge expired + * firewall rules. +*/ +void +check_firewall_rules(fko_srv_options_t *opts) +{ + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + char cmd_out[STANDARD_CMD_OUT_BUFSIZE]; + char exp_str[12]; + char rule_num_str[6]; + char *ndx, *rn_start, *rn_end, *tmp_mark; + + int i, res, rn_offset; + time_t now, rule_exp, min_exp = 0; + + struct fw_chain *ch = opts->fw_config->chain; + + time(&now); + + /* Iterate over each chain and look for active rules to delete. + */ + for(i = 0; i < NUM_FWKNOP_ACCESS_TYPES; i++) + { + /* Just in case we somehow lose track and fall out-of-whack, + * we be the hero and reset it to zero. + * (poet but don't know it :-o ) + */ + if(ch[i].active_rules < 0) + ch[i].active_rules = 0; + + /* If there are no active rules or we have not yet + * reached our expected next expire time, continue. + */ + if(ch[i].active_rules == 0 || ch[i].next_expire > now) + continue; + + rn_offset = 0; + + /* There should be a rule to delete. Get the current list of + * rules for this chain and delete the ones that are expired. + */ + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_LIST_RULES_ARGS, + opts->fw_config->fw_command, + ch[i].table, + ch[i].to_chain + ); + + memset(cmd_out, 0x0, STANDARD_CMD_OUT_BUFSIZE); + + res = run_extcmd(cmd_buf, cmd_out, STANDARD_CMD_OUT_BUFSIZE, 0); + + if(!EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, cmd_out); + continue; + } + + if(opts->verbose > 2) + log_msg(LOG_INFO, "RES=%i, CMD_BUF: %s\nRULES LIST: %s", res, cmd_buf, cmd_out); + + ndx = strstr(cmd_out, "_exp_"); + if(ndx == NULL) + { + /* we did not find an expected rule. + */ + log_msg(LOG_ERR, + "Did not find expire comment in rules list %i.\n", i); + + ch[i].active_rules--; + continue; + } + + /* walk the list and process rules as needed. + */ + while (ndx != NULL) { + /* Jump forward and extract the timestamp + */ + ndx +=5; + + /* remember this spot for when we look for the next + * rule. + */ + tmp_mark = ndx; + + strlcpy(exp_str, ndx, 11); + rule_exp = (time_t)atoll(exp_str); + +//fprintf(stderr, "RULE_EXP=%u, NOW=%u\n", rule_exp, now); + if(rule_exp <= now) + { + /* Backtrack and get the rule number and delete it. + */ + rn_start = ndx; + while(--rn_start > cmd_out) + { + if(*rn_start == '\n') + break; + } + + if(*rn_start != '\n') + { + /* This should not happen. But if it does, complain, + * decrement the active rule value, and go on. + */ + log_msg(LOG_ERR, + "Rule parse error while finding rule line start in chain %i", i); + + ch[i].active_rules--; + break; + } + rn_start++; + + rn_end = strchr(rn_start, ' '); + if(rn_end == NULL) + { + /* This should not happen. But if it does, complain, + * decrement the active rule value, and go on. + */ + log_msg(LOG_ERR, + "Rule parse error while finding rule number in chain %i", i); + + ch[i].active_rules--; + break; + } + + strlcpy(rule_num_str, rn_start, (rn_end - rn_start)+1); + + memset(cmd_buf, 0x0, CMD_BUFSIZE); + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, + opts->fw_config->fw_command, + ch[i].table, + ch[i].to_chain, + atoi(rule_num_str) - rn_offset + ); + + +//fprintf(stderr, "DELETE RULE CMD: %s\n", cmd_buf); + res = run_extcmd(cmd_buf, err, CMD_BUFSIZE, 0); + if(EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_INFO, "Removed rule %s from %s with expire time of %u.", + rule_num_str, ch[i].to_chain, rule_exp + ); + + rn_offset++; + ch[i].active_rules--; + } + else + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err); + + } + else + { + /* Track the minimum future rule expire time. + */ + if(rule_exp > now) + min_exp = (min_exp < rule_exp) ? min_exp : rule_exp; + } + + /* Push our tracking index forward beyond (just processed) _exp_ + * string so we can continue to the next rule in the list. + */ + ndx = strstr(tmp_mark, "_exp_"); + } + + /* Set the next pending expire time accordingly. 0 if there are no + * more rules, or whatever the next expected (min_exp) time will be. + */ + if(ch[i].active_rules < 1) + ch[i].next_expire = 0; + else if(min_exp) + ch[i].next_expire = min_exp; + } +} + +#endif /* FIREWALL_IPTABLES */ + +/***EOF***/ diff --git a/server/fw_util_iptables.h b/server/fw_util_iptables.h new file mode 100644 index 00000000..bbeb92e9 --- /dev/null +++ b/server/fw_util_iptables.h @@ -0,0 +1,47 @@ +/* $Id$ + ***************************************************************************** + * + * File: fw_util_iptables.h + * + * Author: Damien Stuart (dstuart@dstuart.org) + * + * Purpose: Header file for fw_util_iptables.c. + * + * Copyright (C) 2010 Damien Stuart (dstuart@dstuart.org) + * + * License (GNU Public License): + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + ***************************************************************************** +*/ +#ifndef FW_UTIL_IPTABLES_H +#define FW_UTIL_IPTABLES_H + +#define SNAT_TARGET_BUFSIZE 64 + +/* iptables command args +*/ +#define IPT_ADD_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -m comment --comment _exp_%u -j %s 2>&1" +#define IPT_ADD_OUT_RULE_ARGS "-t %s -A %s -p %i -d %s --sport %i -m comment --comment _exp_%u -j %s 2>&1" +#define IPT_ADD_FWD_RULE_ARGS "-t %s -A %s -p %i -s %s -d %s --dport %i -m comment --comment _exp_%u -j %s 2>&1" +#define IPT_ADD_DNAT_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -m comment --comment _exp_%u -j %s --to-destination %s:%i 2>&1" +#define IPT_ADD_SNAT_RULE_ARGS "-t %s -A %s -p %i -d %s --dport %i -m comment --comment _exp_%u -j %s %s 2>&1" +#define IPT_DEL_RULE_ARGS "-t %s -D %s %i 2>&1" +#define IPT_NEW_CHAIN_ARGS "-t %s -N %s 2>&1" +#define IPT_FLUSH_CHAIN_ARGS "-t %s -F %s 2>&1" +#define IPT_DEL_CHAIN_ARGS "-t %s -X %s 2>&1" +#define IPT_ADD_JUMP_RULE_ARGS "-t %s -I %s %i -j %s 2>&1" +#define IPT_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n 2>&1" + +#endif /* FW_UTIL_IPTABLES_H */ + +/***EOF***/ diff --git a/server/fwknopd.c b/server/fwknopd.c index 748cc758..20fcee01 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -585,12 +585,12 @@ write_pid_file(fko_srv_options_t *opts) * error, another instance already has the lock. So we grab * the pid from the existing lock file, complain and bail. */ - lck_res = flock(op_fd, LOCK_EX|LOCK_NB); + lck_res = lockf(op_fd, F_TLOCK, 0); if(lck_res == -1) { - if(errno != EWOULDBLOCK) + if(errno != EAGAIN) { - perror("Unexpected error from flock: "); + perror("Unexpected error from lockf: "); return -1; } diff --git a/server/fwknopd.conf b/server/fwknopd.conf index e5eee8c6..ae2b2207 100644 --- a/server/fwknopd.conf +++ b/server/fwknopd.conf @@ -259,6 +259,6 @@ # System binaries # -#EXE_IPTABLES /sbin/iptables; +#FIREWALL_EXE /sbin/iptables; ###EOF### diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 4d46c8b3..c0fe1fe8 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -160,8 +160,7 @@ enum { CONF_ACCESS_FILE, CONF_FWKNOP_PID_FILE, CONF_DIGEST_FILE, - CONF_EXE_IPTABLES, - CONF_EXE_IPFW, + CONF_FIREWALL_EXE, CONF_GPG_HOME_DIR, @@ -220,8 +219,7 @@ static char *config_map[NUMBER_OF_CONFIG_ENTRIES] = { "ACCESS_FILE", "FWKNOP_PID_FILE", "DIGEST_FILE", - "EXE_IPTABLES", - "EXE_IPFW", + "FIREWALL_EXE", "GPG_HOME_DIR", }; diff --git a/server/pcap_capture.c b/server/pcap_capture.c index 91c11c5f..ed8069b8 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -76,7 +76,9 @@ pcap_capture(fko_srv_options_t *opts) /* We are only interested on seeing packets coming into the interface. */ if (pcap_setdirection(pcap, PCAP_D_IN) < 0) - log_msg(LOG_WARNING, "* Warning: pcap error on setdirection"); + if(opts->verbose) + log_msg(LOG_WARNING, "* Warning: pcap error on setdirection: %s.", + pcap_geterr(pcap)); if (pcap == NULL) {