diff --git a/CREDITS b/CREDITS index c5094215..d8690be7 100644 --- a/CREDITS +++ b/CREDITS @@ -199,3 +199,13 @@ Bill Stubbs following platform: BeagleBone Black rev C running 3.8.13-bone50 #1 SMP Tue May 13 13:24:52 UTC 2014 armv7l GNU/Linux + +Grant Pannell + - Submitted a patch to add a new access.conf variable "DESTINATION" in + order to define the destination address for which an SPA packet will be + accepted. The string "ANY" is also accepted if a valid SPA packet should + be honored to any destination IP. Similarly to the "SOURCE" variable, + networks should be specified in CIDR notation (e.g. "192.168.10.0/24"), + and individual IP addresses can be specified as well. Also, multiple IP's + and/or networks can be defined as a comma separated list (e.g. + "192.168.10.0/24,10.1.1.123"). diff --git a/ChangeLog b/ChangeLog index 4e17e5ce..3a263de7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,12 @@ fwknop-2.6.5 (11//2014): + - [server] (Grant Pannell) Added a new access.conf variable "DESTINATION" + to define the destination address for which an SPA packet will be + accepted. The string "ANY" is also accepted if a valid SPA packet should + be honored to any destination IP. Similarly to the "SOURCE" variable, + networks should be specified in CIDR notation (e.g. "192.168.10.0/24"), + and individual IP addresses can be specified as well. Also, multiple IP's + and/or networks can be defined as a comma separated list (e.g. + "192.168.10.0/24,10.1.1.123"). - [server] Bug fix to ensure that proper bounds are enforced when importing digest cache files from previous fwknopd executions. This bug was discovered through fuzzing with American Fuzzy Lop (AFL) as driven diff --git a/Makefile.am b/Makefile.am index de4b6039..11abd34d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -314,6 +314,12 @@ EXTRA_DIST = \ test/conf/firewd_snat_fwknopd.conf \ test/conf/ipt_snat_no_translate_ip_fwknopd.conf \ test/conf/firewd_snat_no_translate_ip_fwknopd.conf \ + test/conf/destination_rule_fwknopd.conf \ + test/conf/hmac_spa_destination_access.conf \ + test/conf/hmac_spa_destination2_access.conf \ + test/conf/hmac_spa_destination3_access.conf \ + test/conf/hmac_spa_destination4_access.conf \ + test/conf/hmac_spa_destination5_access.conf \ test/conf/spa_replay.pcap \ test/conf/fcs_spa.pcap \ test/fko-wrapper/Makefile \ diff --git a/doc/fwknopd.man.asciidoc b/doc/fwknopd.man.asciidoc index 6a503b50..7707be27 100644 --- a/doc/fwknopd.man.asciidoc +++ b/doc/fwknopd.man.asciidoc @@ -384,6 +384,15 @@ See the '@sysconfdir@/fwknop/fwknopd.conf' file for the full list and correspond *SYSLOG_FACILITY* '':: Override syslog facility. The ``SYSLOG_FACILITY'' variable can be set to one of ``LOG_LOCAL{0-7}'' or ``LOG_DAEMON'' (the default). + +*ENABLE_DESTINATION_RULE* '':: + Controls whether *fwknopd* will set the destination field on the firewall + rule to the destination address specified on the incoming SPA packet. + This is useful for interfaces with multiple IP addresses hosting separate + services. If ``ENABLE_IPT_OUTPUT'' is set to ``Y'', the source field of + the firewall rule is set. FORWARD and SNAT rules are not affected however, + DNAT rules will also have their destination field set. The default is + ``N'', which sets the destination field to 0.0.0.0/0 (any). *FWKNOP_RUN_DIR* '':: Specify the directory where *fwknopd* writes run time state files. The @@ -411,6 +420,15 @@ directive starts a new stanza. and individual IP addresses can be specified as well. Also, multiple IP's and/or networks can be defined as a comma separated list (e.g. ``192.168.10.0/24,10.1.1.123'') + +*DESTINATION* '':: + This defines the destination address for which the SPA packet will be + accepted. The string ``ANY'' is also accepted if a valid SPA packet + should be honored to any destination IP. + Networks should be specified in CIDR notation (e.g. ``192.168.10.0/24''), + and individual IP addresses can be specified as well. Also, multiple + IP's and/or networks can be defined as a comma separated list (e.g. + ``192.168.10.0/24,10.1.1.123'') *OPEN_PORTS* ',...,':: Define a set of ports and protocols (tcp or udp) that will be diff --git a/server/access.c b/server/access.c index eb8c9df2..c5901da9 100644 --- a/server/access.c +++ b/server/access.c @@ -229,7 +229,7 @@ add_acc_force_snat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char * * comparisons of incoming source IPs against this mask. */ static int -add_source_mask(fko_srv_options_t *opts, acc_stanza_t *acc, const char *ip) +add_int_ent(acc_int_list_t **ilist, const char *ip) { char *ndx; char ip_str[MAX_IPV4_STR_LEN] = {0}; @@ -247,7 +247,7 @@ add_source_mask(fko_srv_options_t *opts, acc_stanza_t *acc, const char *ip) log_msg(LOG_ERR, "[*] Fatal memory allocation error adding stanza source_list entry" ); - clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + exit(EXIT_FAILURE); } /* Convert the IP data into the appropriate IP + (optional) mask @@ -370,13 +370,13 @@ add_source_mask(fko_srv_options_t *opts, acc_stanza_t *acc, const char *ip) /* If this is not the first entry, we walk our pointer to the * end of the list. */ - if(acc->source_list == NULL) + if(*ilist == NULL) { - acc->source_list = new_sle; + *ilist = new_sle; } else { - tmp_sle = acc->source_list; + tmp_sle = *ilist; do { last_sle = tmp_sle; @@ -391,13 +391,13 @@ add_source_mask(fko_srv_options_t *opts, acc_stanza_t *acc, const char *ip) /* Expand the access SOURCE string to a list of masks. */ static int -expand_acc_source(fko_srv_options_t *opts, acc_stanza_t *acc) +expand_acc_int_list(acc_int_list_t **ilist, char *ip) { char *ndx, *start; char buf[ACCESS_BUF_LEN] = {0}; int res = 1; - start = acc->source; + start = ip; for(ndx = start; *ndx; ndx++) { @@ -413,7 +413,7 @@ expand_acc_source(fko_srv_options_t *opts, acc_stanza_t *acc) strlcpy(buf, start, (ndx-start)+1); - res = add_source_mask(opts, acc, buf); + res = add_int_ent(ilist, buf); if(res == 0) return res; @@ -431,7 +431,7 @@ expand_acc_source(fko_srv_options_t *opts, acc_stanza_t *acc) strlcpy(buf, start, (ndx-start)+1); - res = add_source_mask(opts, acc, buf); + res = add_int_ent(ilist, buf); return res; } @@ -504,7 +504,7 @@ add_port_list_ent(acc_port_list_t **plist, char *port_str) if((new_plist = calloc(1, sizeof(acc_port_list_t))) == NULL) { log_msg(LOG_ERR, - "[*] Fatal memory allocation error adding stanza source_list entry" + "[*] Fatal memory allocation error adding stanza port_list entry" ); exit(EXIT_FAILURE); } @@ -677,7 +677,7 @@ expand_acc_string_list(acc_string_list_t **stlist, char *stlist_str) /* Free the acc source_list */ static void -free_acc_source_list(acc_int_list_t *sle) +free_acc_int_list(acc_int_list_t *sle) { acc_int_list_t *last_sle; @@ -747,7 +747,13 @@ free_acc_stanza_data(acc_stanza_t *acc) if(acc->source != NULL) { free(acc->source); - free_acc_source_list(acc->source_list); + free_acc_int_list(acc->source_list); + } + + if(acc->destination != NULL) + { + free(acc->destination); + free_acc_int_list(acc->destination_list); } if(acc->open_ports != NULL) @@ -839,11 +845,20 @@ expand_acc_ent_lists(fko_srv_options_t *opts) { /* Expand the source string to 32-bit integer IP + masks for each entry. */ - if(expand_acc_source(opts, acc) == 0) + if(expand_acc_int_list(&(acc->source_list), acc->source) == 0) { log_msg(LOG_ERR, "[*] Fatal invalid SOURCE in access stanza"); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } + + if(acc->destination != NULL && strlen(acc->destination)) + { + if(expand_acc_int_list(&(acc->destination_list), acc->destination) == 0) + { + log_msg(LOG_ERR, "[*] Fatal invalid DESTINATION in access stanza"); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + } /* Now expand the open_ports string. */ @@ -1290,6 +1305,14 @@ parse_access_file(fko_srv_options_t *opts) */ continue; } + else if(CONF_VAR_IS(var, "DESTINATION")) + { + if(add_acc_string(&(curr_acc->destination), val) != SUCCESS) + { + fclose(file_ptr); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + } else if(CONF_VAR_IS(var, "OPEN_PORTS")) { if(add_acc_string(&(curr_acc->open_ports), val) != SUCCESS) @@ -1729,19 +1752,19 @@ parse_access_file(fko_srv_options_t *opts) } int -compare_addr_list(acc_int_list_t *source_list, const uint32_t ip) +compare_addr_list(acc_int_list_t *ip_list, const uint32_t ip) { int match = 0; - while(source_list) + while(ip_list) { - if((ip & source_list->mask) == (source_list->maddr & source_list->mask)) + if((ip & ip_list->mask) == (ip_list->maddr & ip_list->mask)) { match = 1; break; } - source_list = source_list->next; + ip_list = ip_list->next; } return(match); @@ -1898,6 +1921,7 @@ dump_access_list(const fko_srv_options_t *opts) fprintf(stdout, "SOURCE (%i): %s\n" "==============================================================\n" + " DESTINATION: %s\n" " OPEN_PORTS: %s\n" " RESTRICT_PORTS: %s\n" " KEY: %s\n" @@ -1928,6 +1952,7 @@ dump_access_list(const fko_srv_options_t *opts) " GPG_FINGERPRINT_ID: %s\n", ++i, acc->source, + (acc->destination == NULL) ? "" : acc->destination, (acc->open_ports == NULL) ? "" : acc->open_ports, (acc->restrict_ports == NULL) ? "" : acc->restrict_ports, (acc->key == NULL) ? "" : "", diff --git a/server/access.conf b/server/access.conf index f61ad872..17f7627e 100644 --- a/server/access.conf +++ b/server/access.conf @@ -36,6 +36,19 @@ # be honored from any source IP. # +# DESTINATION +# +# This defines the destination address for which a SPA packet will be accepted. +# Networks should be specified in CIDR (e.g. "192.168.10.0/24") notation. +# Individual IP addresses can be specified as well. +# +# Also, multiple IP’s and/or networks can be defined as a comma-separated +# list (e.g. "192.168.10.0/24,10.1.1.123"). +# +# The string "ANY" is also accepted if a valid authorization packet should +# be honored to any destination IP. +# + # OPEN_PORTS , ..., config[CONF_ENABLE_DIGEST_PERSISTENCE] == NULL) set_config_entry(opts, CONF_ENABLE_DIGEST_PERSISTENCE, DEF_ENABLE_DIGEST_PERSISTENCE); + + /* Enable destination rule. + */ + if(opts->config[CONF_ENABLE_DESTINATION_RULE] == NULL) + set_config_entry(opts, CONF_ENABLE_DESTINATION_RULE, + DEF_ENABLE_DESTINATION_RULE); /* Max sniff bytes. */ diff --git a/server/fw_util_firewalld.c b/server/fw_util_firewalld.c index 908a4dd0..5fb054b9 100644 --- a/server/fw_util_firewalld.c +++ b/server/fw_util_firewalld.c @@ -70,14 +70,15 @@ chop_newline(char *str) static int rule_exists_no_chk_support(const fko_srv_options_t * const opts, const struct fw_chain * const fwc, const unsigned int proto, - const char * const ip, const unsigned int port, - const unsigned int exp_ts) + const char * const srcip, const char * const dstip, + const unsigned int port, const unsigned int exp_ts) { int rule_exists=0, rule_num=0, rtmp=0; char cmd_buf[CMD_BUFSIZE] = {0}; char target_search[CMD_BUFSIZE] = {0}; char proto_search[CMD_BUFSIZE] = {0}; - char ip_search[CMD_BUFSIZE] = {0}; + char srcip_search[CMD_BUFSIZE] = {0}; + char dstip_search[CMD_BUFSIZE] = {0}; char port_search[CMD_BUFSIZE] = {0}; char exp_ts_search[CMD_BUFSIZE] = {0}; @@ -98,7 +99,11 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, snprintf(port_search, CMD_BUFSIZE-1, ":%u ", port); snprintf(target_search, CMD_BUFSIZE-1, " %s ", fwc->target); - snprintf(ip_search, CMD_BUFSIZE-1, " %s ", ip); + snprintf(srcip_search, CMD_BUFSIZE-1, " %s ", srcip); + if (dstip != NULL) + { + snprintf(dstip_search, CMD_BUFSIZE-1, " %s ", dstip); + } snprintf(exp_ts_search, CMD_BUFSIZE-1, "%u ", exp_ts); /* search for each of the substrings, and require the returned @@ -114,25 +119,28 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, NO_TIMEOUT, proto_search, &pid_status, opts); if(rtmp == rule_num) rtmp = search_extcmd(cmd_buf, WANT_STDERR, - NO_TIMEOUT, ip_search, &pid_status, opts); + NO_TIMEOUT, srcip_search, &pid_status, opts); if(rtmp == rule_num) - rtmp = search_extcmd(cmd_buf, WANT_STDERR, - NO_TIMEOUT, target_search, &pid_status, opts); + rtmp = (dstip == NULL) ? rtmp : search_extcmd(cmd_buf, WANT_STDERR, + NO_TIMEOUT, dstip_search, &pid_status, opts); if(rtmp == rule_num) rtmp = search_extcmd(cmd_buf, WANT_STDERR, - NO_TIMEOUT, port_search, &pid_status, opts); + NO_TIMEOUT, target_search, &pid_status, opts); if(rtmp == rule_num) - rule_exists = 1; + rtmp = search_extcmd(cmd_buf, WANT_STDERR, + NO_TIMEOUT, port_search, &pid_status, opts); + if(rtmp == rule_num) + rule_exists = 1; } if(rule_exists) log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule (already exists", - proto_search, port, ip, exp_ts); + proto_search, port, srcip, exp_ts); else log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule does not exist", - proto_search, port, ip, exp_ts); + proto_search, port, srcip, exp_ts); return(rule_exists); } @@ -174,15 +182,16 @@ rule_exists_chk_support(const fko_srv_options_t * const opts, static int rule_exists(const fko_srv_options_t * const opts, const struct fw_chain * const fwc, const char * const rule, - const unsigned int proto, const char * const ip, - const unsigned int port, const unsigned int exp_ts) + const unsigned int proto, const char * const srcip, + const char * const dstip, const unsigned int port, + const unsigned int exp_ts) { int rule_exists = 0; if(have_firewd_chk_support == 1) rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule); else - rule_exists = rule_exists_no_chk_support(opts, fwc, proto, ip, port, exp_ts); + rule_exists = rule_exists_no_chk_support(opts, fwc, proto, srcip, (opts->fw_config->use_destination ? dstip : NULL), port, exp_ts); if(rule_exists == 1) log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s already exists", @@ -857,6 +866,11 @@ fw_config_init(fko_srv_options_t * const opts) } } } + + if(strncasecmp(opts->config[CONF_ENABLE_DESTINATION_RULE], "Y", 1)==0) + { + fwc.use_destination = 1; + } /* Let us find it via our opts struct as well. */ @@ -1042,13 +1056,14 @@ process_spa_request(const fko_srv_options_t * const opts, in_chain->table, ple->proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP) ple->port, exp_ts, in_chain->target ); if(rule_exists(opts, in_chain, rule_buf, - ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) + ple->proto, spadat->use_src_ip, spadat->pkt_destination_ip, ple->port, exp_ts) == 0) { if(create_rule(opts, in_chain->to_chain, rule_buf)) { @@ -1078,13 +1093,14 @@ process_spa_request(const fko_srv_options_t * const opts, out_chain->table, ple->proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP), ple->port, exp_ts, out_chain->target ); if(rule_exists(opts, out_chain, rule_buf, - ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) + ple->proto, spadat->use_src_ip, spadat->pkt_destination_ip, ple->port, exp_ts) == 0) { if(create_rule(opts, out_chain->to_chain, rule_buf)) { @@ -1151,6 +1167,7 @@ process_spa_request(const fko_srv_options_t * const opts, in_chain->table, fst_proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP), nat_port, exp_ts, in_chain->target @@ -1166,7 +1183,7 @@ process_spa_request(const fko_srv_options_t * const opts, add_jump_rule(opts, FIREWD_INPUT_ACCESS); if(rule_exists(opts, in_chain, rule_buf, - fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0) + fst_proto, spadat->use_src_ip, spadat->pkt_destination_ip, nat_port, exp_ts) == 0) { if(create_rule(opts, in_chain->to_chain, rule_buf)) { @@ -1209,7 +1226,7 @@ process_spa_request(const fko_srv_options_t * const opts, ); if(rule_exists(opts, fwd_chain, rule_buf, fst_proto, - spadat->use_src_ip, nat_port, exp_ts) == 0) + spadat->use_src_ip, nat_ip, nat_port, exp_ts) == 0) { if(create_rule(opts, fwd_chain->to_chain, rule_buf)) { @@ -1245,6 +1262,7 @@ process_spa_request(const fko_srv_options_t * const opts, dnat_chain->table, fst_proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : FIREWD_ANY_IP), fst_port, exp_ts, dnat_chain->target, @@ -1253,7 +1271,7 @@ process_spa_request(const fko_srv_options_t * const opts, ); if(rule_exists(opts, dnat_chain, rule_buf, fst_proto, - spadat->use_src_ip, fst_port, exp_ts) == 0) + spadat->use_src_ip, spadat->pkt_destination_ip, fst_port, exp_ts) == 0) { if(create_rule(opts, dnat_chain->to_chain, rule_buf)) { @@ -1333,7 +1351,7 @@ process_spa_request(const fko_srv_options_t * const opts, ); if(rule_exists(opts, snat_chain, rule_buf, fst_proto, - spadat->use_src_ip, nat_port, exp_ts) == 0) + spadat->use_src_ip, NULL, nat_port, exp_ts) == 0) { if(create_rule(opts, snat_chain->to_chain, rule_buf)) { diff --git a/server/fw_util_firewalld.h b/server/fw_util_firewalld.h index 8b17c4c9..b91131d2 100644 --- a/server/fw_util_firewalld.h +++ b/server/fw_util_firewalld.h @@ -42,10 +42,10 @@ /* firewalld command args */ #define FIREWD_CHK_RULE_ARGS "-C %s %s" /* the other macros add SH_REDIR if necessary */ -#define FIREWD_RULE_ARGS "-t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR -#define FIREWD_OUT_RULE_ARGS "-t %s -p %i -d %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR +#define FIREWD_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR +#define FIREWD_OUT_RULE_ARGS "-t %s -p %i -d %s -s %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR #define FIREWD_FWD_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR -#define FIREWD_DNAT_RULE_ARGS "-t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i" SH_REDIR +#define FIREWD_DNAT_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i" SH_REDIR #define FIREWD_SNAT_RULE_ARGS "-t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s" SH_REDIR #define FIREWD_TMP_COMMENT_ARGS "-t %s -I %s %i -s 127.0.0.2 -m comment --comment " TMP_COMMENT " -j %s" SH_REDIR #define FIREWD_TMP_CHK_RULE_ARGS "-t %s -I %s %i -s 127.0.0.2 -p udp -j %s" SH_REDIR @@ -60,6 +60,7 @@ #define FIREWD_DEL_JUMP_RULE_ARGS "-t %s -D %s -j %s" SH_REDIR /* let firewalld work out the rule number */ #define FIREWD_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n" SH_REDIR #define FIREWD_LIST_ALL_RULES_ARGS "-t %s -v -n -L --line-numbers" SH_REDIR +#define FIREWD_ANY_IP "0.0.0.0/0" int validate_firewd_chain_conf(const char * const chain_str); diff --git a/server/fw_util_ipf.c b/server/fw_util_ipf.c index 1e875b91..dbb4f499 100644 --- a/server/fw_util_ipf.c +++ b/server/fw_util_ipf.c @@ -72,7 +72,11 @@ fw_config_init(fko_srv_options_t *opts) /* Set our firewall exe command path (iptables in most cases). */ strlcpy(fwc.fw_command, opts->config[CONF_FIREWALL_EXE], sizeof(fwc.fw_command)); - + + if(strncasecmp(opts->config[CONF_ENABLE_DESTINATION_RULE], "Y", 1)==0) + { + fwc.use_destination = 1; + } /* Let us find it via our opts struct as well. */ diff --git a/server/fw_util_ipf.h b/server/fw_util_ipf.h index 966607d5..cd023b28 100644 --- a/server/fw_util_ipf.h +++ b/server/fw_util_ipf.h @@ -40,6 +40,7 @@ #define IPF_ADD_SNAT_RULE_ARGS "" #define IPF_DEL_RULE_ARGS "" #define IPF_LIST_RULES_ARGS "" +#define IPF_ANY_IP "" #endif /* FW_UTIL_IPF_H */ diff --git a/server/fw_util_ipfw.c b/server/fw_util_ipfw.c index 932164f9..1025b4e6 100644 --- a/server/fw_util_ipfw.c +++ b/server/fw_util_ipfw.c @@ -238,6 +238,11 @@ fw_config_init(fko_srv_options_t * const opts) RCHK_MAX_IPFW_PURGE_INTERVAL); return 0; } + + if(strncasecmp(opts->config[CONF_ENABLE_DESTINATION_RULE], "Y", 1)==0) + { + fwc.use_destination = 1; + } /* Let us find it via our opts struct as well. */ @@ -532,6 +537,7 @@ process_spa_request(const fko_srv_options_t * const opts, fwc.active_set_num, ple->proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : IPFW_ANY_IP), ple->port, exp_ts ); diff --git a/server/fw_util_ipfw.h b/server/fw_util_ipfw.h index fa716761..031221fa 100644 --- a/server/fw_util_ipfw.h +++ b/server/fw_util_ipfw.h @@ -40,13 +40,14 @@ enum { /* ipfw command args */ -#define IPFW_ADD_RULE_ARGS "add %u set %u pass %u from %s to me dst-port %u setup keep-state // " EXPIRE_COMMENT_PREFIX "%u" +#define IPFW_ADD_RULE_ARGS "add %u set %u pass %u from %s to %s dst-port %u setup keep-state // " EXPIRE_COMMENT_PREFIX "%u" #define IPFW_ADD_CHECK_STATE_ARGS "add %u set %u check-state" #define IPFW_MOVE_RULE_ARGS "set move rule %u to %u" #define IPFW_MOVE_SET_ARGS "set move %u to %u" #define IPFW_DISABLE_SET_ARGS "set disable %u" #define IPFW_LIST_ALL_RULES_ARGS "list" #define IPFW_DEL_RULE_SET_ARGS "delete set %u" +#define IPFW_ANY_IP "me" #ifdef __APPLE__ #define IPFW_DEL_RULE_ARGS "delete %u" //--DSS diff args diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index 8492fa83..55fb6e84 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -70,14 +70,15 @@ chop_newline(char *str) static int rule_exists_no_chk_support(const fko_srv_options_t * const opts, const struct fw_chain * const fwc, const unsigned int proto, - const char * const ip, const unsigned int port, - const unsigned int exp_ts) + const char * const srcip, const char * const dstip, + const unsigned int port, const unsigned int exp_ts) { int rule_exists=0, rule_num=0, rtmp=0; char cmd_buf[CMD_BUFSIZE] = {0}; char target_search[CMD_BUFSIZE] = {0}; char proto_search[CMD_BUFSIZE] = {0}; - char ip_search[CMD_BUFSIZE] = {0}; + char srcip_search[CMD_BUFSIZE] = {0}; + char dstip_search[CMD_BUFSIZE] = {0}; char port_search[CMD_BUFSIZE] = {0}; char exp_ts_search[CMD_BUFSIZE] = {0}; @@ -109,7 +110,11 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, snprintf(port_search, CMD_BUFSIZE-1, ":%u ", port); snprintf(target_search, CMD_BUFSIZE-1, " %s ", fwc->target); - snprintf(ip_search, CMD_BUFSIZE-1, " %s ", ip); + snprintf(srcip_search, CMD_BUFSIZE-1, " %s ", srcip); + if (dstip != NULL) + { + snprintf(dstip_search, CMD_BUFSIZE-1, " %s ", dstip); + } snprintf(exp_ts_search, CMD_BUFSIZE-1, "%u ", exp_ts); /* search for each of the substrings, and require the returned @@ -125,25 +130,28 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts, NO_TIMEOUT, proto_search, &pid_status, opts); if(rtmp == rule_num) rtmp = search_extcmd(cmd_buf, WANT_STDERR, - NO_TIMEOUT, ip_search, &pid_status, opts); + NO_TIMEOUT, srcip_search, &pid_status, opts); if(rtmp == rule_num) - rtmp = search_extcmd(cmd_buf, WANT_STDERR, - NO_TIMEOUT, target_search, &pid_status, opts); + rtmp = (dstip == NULL) ? rtmp : search_extcmd(cmd_buf, WANT_STDERR, + NO_TIMEOUT, dstip_search, &pid_status, opts); if(rtmp == rule_num) rtmp = search_extcmd(cmd_buf, WANT_STDERR, - NO_TIMEOUT, port_search, &pid_status, opts); + NO_TIMEOUT, target_search, &pid_status, opts); if(rtmp == rule_num) - rule_exists = 1; + rtmp = search_extcmd(cmd_buf, WANT_STDERR, + NO_TIMEOUT, port_search, &pid_status, opts); + if(rtmp == rule_num) + rule_exists = 1; } if(rule_exists) log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule (already exists", - proto_search, port, ip, exp_ts); + proto_search, port, srcip, exp_ts); else log_msg(LOG_DEBUG, "rule_exists_no_chk_support() %s %u -> %s expires: %u rule does not exist", - proto_search, port, ip, exp_ts); + proto_search, port, srcip, exp_ts); return(rule_exists); } @@ -185,15 +193,16 @@ rule_exists_chk_support(const fko_srv_options_t * const opts, static int rule_exists(const fko_srv_options_t * const opts, const struct fw_chain * const fwc, const char * const rule, - const unsigned int proto, const char * const ip, - const unsigned int port, const unsigned int exp_ts) + const unsigned int proto, const char * const srcip, + const char * const dstip, const unsigned int port, + const unsigned int exp_ts) { int rule_exists = 0; if(have_ipt_chk_support == 1) rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule); else - rule_exists = rule_exists_no_chk_support(opts, fwc, proto, ip, port, exp_ts); + rule_exists = rule_exists_no_chk_support(opts, fwc, proto, srcip, (opts->fw_config->use_destination ? dstip : NULL), port, exp_ts); if(rule_exists == 1) log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s already exists", @@ -859,6 +868,11 @@ fw_config_init(fko_srv_options_t * const opts) } } } + + if(strncasecmp(opts->config[CONF_ENABLE_DESTINATION_RULE], "Y", 1)==0) + { + fwc.use_destination = 1; + } /* Let us find it via our opts struct as well. */ @@ -1044,13 +1058,14 @@ process_spa_request(const fko_srv_options_t * const opts, in_chain->table, ple->proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), ple->port, exp_ts, in_chain->target ); if(rule_exists(opts, in_chain, rule_buf, - ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) + ple->proto, spadat->use_src_ip, spadat->pkt_destination_ip, ple->port, exp_ts) == 0) { if(create_rule(opts, in_chain->to_chain, rule_buf)) { @@ -1080,13 +1095,14 @@ process_spa_request(const fko_srv_options_t * const opts, out_chain->table, ple->proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), ple->port, exp_ts, out_chain->target ); if(rule_exists(opts, out_chain, rule_buf, - ple->proto, spadat->use_src_ip, ple->port, exp_ts) == 0) + ple->proto, spadat->use_src_ip, spadat->pkt_destination_ip, ple->port, exp_ts) == 0) { if(create_rule(opts, out_chain->to_chain, rule_buf)) { @@ -1153,6 +1169,7 @@ process_spa_request(const fko_srv_options_t * const opts, in_chain->table, fst_proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), nat_port, exp_ts, in_chain->target @@ -1168,7 +1185,7 @@ process_spa_request(const fko_srv_options_t * const opts, add_jump_rule(opts, IPT_INPUT_ACCESS); if(rule_exists(opts, in_chain, rule_buf, - fst_proto, spadat->use_src_ip, nat_port, exp_ts) == 0) + fst_proto, spadat->use_src_ip, spadat->pkt_destination_ip, nat_port, exp_ts) == 0) { if(create_rule(opts, in_chain->to_chain, rule_buf)) { @@ -1211,7 +1228,7 @@ process_spa_request(const fko_srv_options_t * const opts, ); if(rule_exists(opts, fwd_chain, rule_buf, fst_proto, - spadat->use_src_ip, nat_port, exp_ts) == 0) + spadat->use_src_ip, nat_ip, nat_port, exp_ts) == 0) { if(create_rule(opts, fwd_chain->to_chain, rule_buf)) { @@ -1247,6 +1264,7 @@ process_spa_request(const fko_srv_options_t * const opts, dnat_chain->table, fst_proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP), fst_port, exp_ts, dnat_chain->target, @@ -1255,7 +1273,7 @@ process_spa_request(const fko_srv_options_t * const opts, ); if(rule_exists(opts, dnat_chain, rule_buf, fst_proto, - spadat->use_src_ip, fst_port, exp_ts) == 0) + spadat->use_src_ip, spadat->pkt_destination_ip, fst_port, exp_ts) == 0) { if(create_rule(opts, dnat_chain->to_chain, rule_buf)) { @@ -1335,7 +1353,7 @@ process_spa_request(const fko_srv_options_t * const opts, ); if(rule_exists(opts, snat_chain, rule_buf, fst_proto, - spadat->use_src_ip, nat_port, exp_ts) == 0) + spadat->use_src_ip, NULL, nat_port, exp_ts) == 0) { if(create_rule(opts, snat_chain->to_chain, rule_buf)) { diff --git a/server/fw_util_iptables.h b/server/fw_util_iptables.h index 626e0ec5..27794efc 100644 --- a/server/fw_util_iptables.h +++ b/server/fw_util_iptables.h @@ -42,10 +42,10 @@ /* iptables command args */ #define IPT_CHK_RULE_ARGS "-C %s %s" /* the other macros add SH_REDIR if necessary */ -#define IPT_RULE_ARGS "-t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR -#define IPT_OUT_RULE_ARGS "-t %s -p %i -d %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR +#define IPT_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR +#define IPT_OUT_RULE_ARGS "-t %s -p %i -d %s -s %s --sport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR #define IPT_FWD_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s" SH_REDIR -#define IPT_DNAT_RULE_ARGS "-t %s -p %i -s %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i" SH_REDIR +#define IPT_DNAT_RULE_ARGS "-t %s -p %i -s %s -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s --to-destination %s:%i" SH_REDIR #define IPT_SNAT_RULE_ARGS "-t %s -p %i -d %s --dport %i -m comment --comment " EXPIRE_COMMENT_PREFIX "%u -j %s %s" SH_REDIR #define IPT_TMP_COMMENT_ARGS "-t %s -I %s %i -s 127.0.0.2 -m comment --comment " TMP_COMMENT " -j %s" SH_REDIR #define IPT_TMP_CHK_RULE_ARGS "-t %s -I %s %i -s 127.0.0.2 -p udp -j %s" SH_REDIR @@ -60,6 +60,7 @@ #define IPT_DEL_JUMP_RULE_ARGS "-t %s -D %s -j %s" SH_REDIR /* let iptables work out the rule number */ #define IPT_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n" SH_REDIR #define IPT_LIST_ALL_RULES_ARGS "-t %s -v -n -L --line-numbers" SH_REDIR +#define IPT_ANY_IP "0.0.0.0/0" int validate_ipt_chain_conf(const char * const chain_str); diff --git a/server/fw_util_pf.c b/server/fw_util_pf.c index 9d76033c..f41bf7a7 100644 --- a/server/fw_util_pf.c +++ b/server/fw_util_pf.c @@ -151,6 +151,11 @@ fw_config_init(fko_srv_options_t * const opts) /* Set the PF anchor name */ strlcpy(fwc.anchor, opts->config[CONF_PF_ANCHOR_NAME], sizeof(fwc.anchor)); + + if(strncasecmp(opts->config[CONF_ENABLE_DESTINATION_RULE], "Y", 1)==0) + { + fwc.use_destination = 1; + } /* Let us find it via our opts struct as well. */ @@ -243,6 +248,7 @@ process_spa_request(const fko_srv_options_t * const opts, snprintf(new_rule, MAX_PF_NEW_RULE_LEN-1, PF_ADD_RULE_ARGS "\n", ple->proto, spadat->use_src_ip, + (fwc.use_destination ? spadat->pkt_destination_ip : PF_ANY_IP), ple->port, exp_ts ); diff --git a/server/fw_util_pf.h b/server/fw_util_pf.h index e1c6f093..9d4901eb 100644 --- a/server/fw_util_pf.h +++ b/server/fw_util_pf.h @@ -32,7 +32,7 @@ #define FW_UTIL_PF_H #define MAX_PF_ANCHOR_SEARCH_LEN (MAX_PF_ANCHOR_LEN+11) /* room for 'anchor "' string */ -#define MAX_PF_NEW_RULE_LEN 120 +#define MAX_PF_NEW_RULE_LEN 140 #if HAVE_EXECVPE #define SH_REDIR "" /* the shell is not used when execvpe() is available */ @@ -42,7 +42,7 @@ /* pf command args */ -#define PF_ADD_RULE_ARGS "pass in quick proto %u from %s to any port %u keep state label " EXPIRE_COMMENT_PREFIX "%u" +#define PF_ADD_RULE_ARGS "pass in quick proto %u from %s to %s port %u keep state label " EXPIRE_COMMENT_PREFIX "%u" #define PF_WRITE_ANCHOR_RULES_ARGS "-a %s -f -" #if HAVE_EXECVPE #define PF_LIST_ANCHOR_RULES_ARGS "-a %s -s rules" @@ -51,6 +51,7 @@ #endif #define PF_ANCHOR_CHECK_ARGS "-s Anchor" SH_REDIR /* to check for fwknop anchor */ #define PF_DEL_ALL_ANCHOR_RULES "-a %s -F all" SH_REDIR +#define PF_ANY_IP "any" #endif /* FW_UTIL_PF_H */ diff --git a/server/fwknopd.8.in b/server/fwknopd.8.in index 7663ecbe..5c28cb3d 100644 --- a/server/fwknopd.8.in +++ b/server/fwknopd.8.in @@ -526,6 +526,13 @@ Specify the directory where writes run time state files\&. The default is \fI@localstatedir@/run\fR\&. .RE +.PP +\fBENABLE_DESTINATION_RULE\fR \fI\fR +.RS 4 +Controls whether +\fBfwknopd\fR +will set the destination field on the firewall rule to the destination address specified on the incoming SPA packet\&. This is useful for interfaces with multiple IP addresses hosting separate services\&. If \(lqENABLE_IPT_OUTPUT\(rq is set to \(lqY\(rq, the source field of the firewall rule is set\&. FORWARD and SNAT rules are not affected however, DNAT rules will also have their destination field set\&. The default is \(lqN\(rq, which sets the destination field to 0\&.0\&.0\&.0/0 (any)\&. +.RE .SS "ACCESS\&.CONF VARIABLES" .sp This section describes the access control directives in the \fI@sysconfdir@/fwknop/access\&.conf\fR file\&. Theses directives define encryption keys and level of access that is granted to \fBfwknop\fR clients that have generated the appropriate encrypted message\&. @@ -539,6 +546,11 @@ This defines the source address from which the SPA packet will be accepted\&. Th definition must start with the \(lqSOURCE\(rq keyword\&. Networks should be specified in CIDR notation (e\&.g\&. \(lq192\&.168\&.10\&.0/24\(rq), and individual IP addresses can be specified as well\&. Also, multiple IP\(cqs and/or networks can be defined as a comma separated list (e\&.g\&. \(lq192\&.168\&.10\&.0/24,10\&.1\&.1\&.123\(rq) .RE .PP +\fBDESTINATION\fR \fI\fR +.RS 4 +This defines the destination address for which the SPA packet will be accepted\&. The string \(lqANY\(rq is also accepted if a valid SPA packet should be honored to any destination IP\&. Networks should be specified in CIDR notation (e\&.g\&. \(lq192\&.168\&.10\&.0/24\(rq), and individual IP addresses can be specified as well\&. Also, multiple IP\(cqs and/or networks can be defined as a comma separated list (e\&.g\&. \(lq192\&.168\&.10\&.0/24,10\&.1\&.1\&.123\(rq) +.RE +.PP \fBOPEN_PORTS\fR \fI,\&...,\fR .RS 4 Define a set of ports and protocols (tcp or udp) that will be opened if a valid knock sequence is seen\&. If this entry is not set, diff --git a/server/fwknopd.conf b/server/fwknopd.conf index 8faeebd6..29ec9e2d 100644 --- a/server/fwknopd.conf +++ b/server/fwknopd.conf @@ -152,6 +152,16 @@ # # ENABLE_PCAP_ANY_DIRECTION N; +# Controls whether fwknopd will set the destination field on the firewall +# rule to the destination address specified on the incoming SPA packet. +# This is useful for interfaces with multiple IP addresses hosting separate +# services. If ENABLE_IPT_OUTPUT is set to "Y", the source field of +# the firewall rule is set. FORWARD and SNAT rules are not affected however, +# DNAT rules will also have their destination field set. The default is +# "N", which sets the destination field to 0.0.0.0/0 (any). +# +# ENABLE_DESTINATION_RULE Y; + ############################################################################## # NOTE: The following EXTERNAL_CMD functionality is not yet implemented. # This is a possible future feature of fwknopd. diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 68a2db2a..84ebc01f 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -110,6 +110,7 @@ #define DEF_UDPSERV_SELECT_TIMEOUT "500000" /* half a second (in microseconds) */ #define DEF_SYSLOG_IDENTITY MY_NAME #define DEF_SYSLOG_FACILITY "LOG_DAEMON" +#define DEF_ENABLE_DESTINATION_RULE "N" #define DEF_FW_ACCESS_TIMEOUT 30 @@ -247,6 +248,7 @@ enum { //CONF_EXTERNAL_CMD_ALARM, //CONF_ENABLE_EXT_CMD_PREFIX, //CONF_EXT_CMD_PREFIX, + CONF_ENABLE_DESTINATION_RULE, #if FIREWALL_FIREWALLD CONF_ENABLE_FIREWD_FORWARDING, CONF_ENABLE_FIREWD_LOCAL_NAT, @@ -348,6 +350,8 @@ typedef struct acc_stanza { char *source; acc_int_list_t *source_list; + char *destination; + acc_int_list_t *destination_list; char *open_ports; acc_port_list_t *oport_list; char *restrict_ports; @@ -449,6 +453,9 @@ typedef struct acc_stanza /* Flag for firewalld SNAT vs. MASQUERADE usage */ unsigned char use_masquerade; + /* Flag for setting destination field in rule + */ + unsigned char use_destination; }; #elif FIREWALL_IPTABLES @@ -496,6 +503,9 @@ typedef struct acc_stanza /* Flag for iptables SNAT vs. MASQUERADE usage */ unsigned char use_masquerade; + /* Flag for setting destination field in rule + */ + unsigned char use_destination; }; #elif FIREWALL_IPFW @@ -512,6 +522,7 @@ typedef struct acc_stanza time_t next_expire; time_t last_purge; char fw_command[MAX_PATH_LEN]; + unsigned char use_destination; }; #elif FIREWALL_PF @@ -523,6 +534,7 @@ typedef struct acc_stanza time_t next_expire; char anchor[MAX_PF_ANCHOR_LEN]; char fw_command[MAX_PATH_LEN]; + unsigned char use_destination; }; #elif FIREWALL_IPF @@ -555,6 +567,7 @@ typedef struct spa_data char *spa_message; char spa_message_src_ip[MAX_IPV4_STR_LEN]; char pkt_source_ip[MAX_IPV4_STR_LEN]; + char pkt_destination_ip[MAX_IPV4_STR_LEN]; char spa_message_remain[1024]; /* --DSS FIXME: arbitrary bounds */ char *nat_access; char *server_auth; diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 544f102e..9163b0a2 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -321,6 +321,9 @@ incoming_spa(fko_srv_options_t *opts) inet_ntop(AF_INET, &(spa_pkt->packet_src_ip), spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip)); + inet_ntop(AF_INET, &(spa_pkt->packet_dst_ip), + spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip)); + /* At this point, we want to validate and (if needed) preprocess the * SPA data and/or to be reasonably sure we have a SPA packet (i.e * try to eliminate obvious non-spa packets). @@ -405,10 +408,14 @@ incoming_spa(fko_srv_options_t *opts) ctx = NULL; } - /* Check for a match for the SPA source IP and the access stanza + /* Check for a match for the SPA source and destination IP and the access stanza */ - if(! compare_addr_list(acc->source_list, ntohl(spa_pkt->packet_src_ip))) + if(! compare_addr_list(acc->source_list, ntohl(spa_pkt->packet_src_ip)) || + (acc->destination_list != NULL && ! compare_addr_list(acc->destination_list, ntohl(spa_pkt->packet_dst_ip)))) { + log_msg(LOG_DEBUG, + "(stanza #%d) SPA packet (%s -> %s) filtered by SOURCE and/or DESTINATION criteria", + stanza_num, spadat.pkt_source_ip, spadat.pkt_destination_ip); acc = acc->next; continue; } diff --git a/test/conf/destination_rule_fwknopd.conf b/test/conf/destination_rule_fwknopd.conf new file mode 100644 index 00000000..670a3ca5 --- /dev/null +++ b/test/conf/destination_rule_fwknopd.conf @@ -0,0 +1 @@ +ENABLE_DESTINATION_RULE Y; diff --git a/test/conf/hmac_spa_destination2_access.conf b/test/conf/hmac_spa_destination2_access.conf new file mode 100644 index 00000000..5ab0f281 --- /dev/null +++ b/test/conf/hmac_spa_destination2_access.conf @@ -0,0 +1,5 @@ +SOURCE ANY +DESTINATION 1.2.3.4, 127.0.0.1, 123.0.0.0/24 +KEY_BASE64 wzNP62oPPgEc+kXDPQLHPOayQBuNbYUTPP+QrErNDmg= +HMAC_KEY_BASE64 Yh+xizBnl6FotC5ec7FanVGClRMlsOAPh2u6eovnerfBVKwaVKzjGoblFMHMc593TNyi0dWn4opLoTIV9q/ttg== +FW_ACCESS_TIMEOUT 3 diff --git a/test/conf/hmac_spa_destination3_access.conf b/test/conf/hmac_spa_destination3_access.conf new file mode 100644 index 00000000..f8482b4a --- /dev/null +++ b/test/conf/hmac_spa_destination3_access.conf @@ -0,0 +1,5 @@ +SOURCE ANY +DESTINATION 1.2.3.4, 123.0.0.0/24, 127.0.0.1/32 +KEY_BASE64 wzNP62oPPgEc+kXDPQLHPOayQBuNbYUTPP+QrErNDmg= +HMAC_KEY_BASE64 Yh+xizBnl6FotC5ec7FanVGClRMlsOAPh2u6eovnerfBVKwaVKzjGoblFMHMc593TNyi0dWn4opLoTIV9q/ttg== +FW_ACCESS_TIMEOUT 3 diff --git a/test/conf/hmac_spa_destination4_access.conf b/test/conf/hmac_spa_destination4_access.conf new file mode 100644 index 00000000..71e79727 --- /dev/null +++ b/test/conf/hmac_spa_destination4_access.conf @@ -0,0 +1,5 @@ +SOURCE ANY +DESTINATION 1.2.3.4 +KEY_BASE64 wzNP62oPPgEc+kXDPQLHPOayQBuNbYUTPP+QrErNDmg= +HMAC_KEY_BASE64 Yh+xizBnl6FotC5ec7FanVGClRMlsOAPh2u6eovnerfBVKwaVKzjGoblFMHMc593TNyi0dWn4opLoTIV9q/ttg== +FW_ACCESS_TIMEOUT 3 diff --git a/test/conf/hmac_spa_destination5_access.conf b/test/conf/hmac_spa_destination5_access.conf new file mode 100644 index 00000000..9ceacfeb --- /dev/null +++ b/test/conf/hmac_spa_destination5_access.conf @@ -0,0 +1,5 @@ +SOURCE ANY +DESTINATION 1.2.3.4, 123.0.0.0/24 +KEY_BASE64 wzNP62oPPgEc+kXDPQLHPOayQBuNbYUTPP+QrErNDmg= +HMAC_KEY_BASE64 Yh+xizBnl6FotC5ec7FanVGClRMlsOAPh2u6eovnerfBVKwaVKzjGoblFMHMc593TNyi0dWn4opLoTIV9q/ttg== +FW_ACCESS_TIMEOUT 3 diff --git a/test/conf/hmac_spa_destination_access.conf b/test/conf/hmac_spa_destination_access.conf new file mode 100644 index 00000000..23d656de --- /dev/null +++ b/test/conf/hmac_spa_destination_access.conf @@ -0,0 +1,5 @@ +SOURCE ANY +DESTINATION ANY +KEY_BASE64 wzNP62oPPgEc+kXDPQLHPOayQBuNbYUTPP+QrErNDmg= +HMAC_KEY_BASE64 Yh+xizBnl6FotC5ec7FanVGClRMlsOAPh2u6eovnerfBVKwaVKzjGoblFMHMc593TNyi0dWn4opLoTIV9q/ttg== +FW_ACCESS_TIMEOUT 3 diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index 686c2f54..93cfe139 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -388,6 +388,12 @@ our %cf = ( 'hmac_simple_keys_access' => "$conf_dir/hmac_simple_keys_access.conf", 'hmac_invalid_type_access' => "$conf_dir/hmac_invalid_type_access.conf", 'hmac_cygwin_access' => "$conf_dir/hmac_no_b64_cygwin_access.conf", + 'spa_destnation' => "$conf_dir/destination_rule_fwknopd.conf", + 'hmac_spa_destination_access' => "$conf_dir/hmac_spa_destination_access.conf", + 'hmac_spa_destination2_access' => "$conf_dir/hmac_spa_destination2_access.conf", + 'hmac_spa_destination3_access' => "$conf_dir/hmac_spa_destination3_access.conf", + 'hmac_spa_destination4_access' => "$conf_dir/hmac_spa_destination4_access.conf", + 'hmac_spa_destination5_access' => "$conf_dir/hmac_spa_destination5_access.conf", 'exp_access' => "$conf_dir/expired_stanza_access.conf", 'future_exp_access' => "$conf_dir/future_expired_stanza_access.conf", 'exp_epoch_access' => "$conf_dir/expired_epoch_stanza_access.conf", diff --git a/test/tests/basic_operations.pl b/test/tests/basic_operations.pl index 91f3ecb1..b334ef3a 100644 --- a/test/tests/basic_operations.pl +++ b/test/tests/basic_operations.pl @@ -3335,6 +3335,38 @@ 'positive_output_matches' => [qr/No\skeys\sfound/], }, + { + 'category' => 'basic operations', + 'subcategory' => 'server', + 'detail' => 'access DESTINATION missing SOURCE', + 'function' => \&server_conf_files, + 'fwknopd_cmdline' => $server_rewrite_conf_files, + 'exec_err' => $YES, + 'server_access_file' => [ + 'DESTINATION 1.1.1.1', + ], + 'server_conf_file' => [ + '### comment line' + ], + 'positive_output_matches' => [qr/not\sfind\svalid\sSOURCE/], + }, + { + 'category' => 'basic operations', + 'subcategory' => 'server', + 'detail' => 'missing access DESTINATION key', + 'function' => \&server_conf_files, + 'fwknopd_cmdline' => $server_rewrite_conf_files, + 'exec_err' => $YES, + 'server_access_file' => [ + 'SOURCE 1.1.1.1', + 'DESTINATION 1.2.3.4', + ], + 'server_conf_file' => [ + '### comment line' + ], + 'positive_output_matches' => [qr/No\skeys\sfound/], + }, + { 'category' => 'basic operations', 'subcategory' => 'server', diff --git a/test/tests/rijndael_hmac.pl b/test/tests/rijndael_hmac.pl index 3f466abc..5ec9d0b9 100644 --- a/test/tests/rijndael_hmac.pl +++ b/test/tests/rijndael_hmac.pl @@ -83,7 +83,74 @@ 'key_file' => $cf{'rc_hmac_b64_key'}, 'client_cycles_per_server_instance' => 3, }, - + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => 'cycle DESTINATION accepted (1)', + 'function' => \&spa_cycle, + 'cmdline' => $default_client_hmac_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'spa_destnation'} " . + "-a $cf{'hmac_spa_destination_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'key_file' => $cf{'rc_hmac_b64_key'}, + 'server_positive_output_matches' => [qr/\b$fake_ip\s.*$loopback_ip\b/], + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => 'cycle DESTINATION accepted (2)', + 'function' => \&spa_cycle, + 'cmdline' => $default_client_hmac_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'spa_destnation'} " . + "-a $cf{'hmac_spa_destination2_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'key_file' => $cf{'rc_hmac_b64_key'}, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => 'cycle DESTINATION accepted (3)', + 'function' => \&spa_cycle, + 'cmdline' => $default_client_hmac_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'spa_destnation'} " . + "-a $cf{'hmac_spa_destination3_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'key_file' => $cf{'rc_hmac_b64_key'}, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => 'cycle DESTINATION filtered (1)', + 'function' => \&spa_cycle, + 'cmdline' => $default_client_hmac_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'spa_destnation'} " . + "-a $cf{'hmac_spa_destination4_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + 'client_pkt_tries' => 2, + 'server_receive_re' => qr/SPA\spacket\s.*filtered\sby\sSOURCE.*DEST/, + 'key_file' => $cf{'rc_hmac_b64_key'}, + }, + { + 'category' => 'Rijndael+HMAC', + 'subcategory' => 'client+server', + 'detail' => 'cycle DESTINATION filtered (2)', + 'function' => \&spa_cycle, + 'cmdline' => $default_client_hmac_args, + 'fwknopd_cmdline' => "$fwknopdCmd -c $cf{'spa_destnation'} " . + "-a $cf{'hmac_spa_destination5_access'} " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + 'client_pkt_tries' => 2, + 'server_receive_re' => qr/SPA\spacket\s.*filtered\sby\sSOURCE.*DEST/, + 'key_file' => $cf{'rc_hmac_b64_key'}, + }, { 'category' => 'Rijndael+HMAC', 'subcategory' => 'client+server',