From 9b7c1a8ce69fe51337458cce4e7b5e9cb3d7654b Mon Sep 17 00:00:00 2001 From: Michael Rash Date: Wed, 30 Nov 2011 20:51:19 -0500 Subject: [PATCH] Added FORCE_NAT mode to the access.conf file This commit adds a new configuration variable "FORCE_NAT" to the access.conf file: For any valid SPA packet, force the requested connection to be NAT'd through to the specified (usually internal) IP and port value. This is useful if there are multiple internal systems running a service such as SSHD, and you want to give transparent access to only one internal system for each stanza in the access.conf file. This way, multiple external users can each directly access only one internal system per SPA key. This commit also implements a few minor code cleanups. --- client/config_init.c | 24 +++---- client/fwknop_common.h | 4 +- client/http_resolve_host.c | 6 +- common/common.h | 4 +- doc/fwknop.man.asciidoc | 4 +- doc/fwknopd.man.asciidoc | 18 ++++-- server/access.c | 51 +++++++++++++-- server/fw_util.h | 2 +- server/fw_util_ipf.c | 4 +- server/fw_util_ipfw.c | 2 +- server/fw_util_iptables.c | 32 ++++++---- server/fw_util_pf.c | 2 +- server/fwknopd.c | 2 +- server/fwknopd_common.h | 8 ++- server/incoming_spa.c | 2 +- server/tcp_server.c | 6 +- test/conf/expired_stanza_access.conf | 2 +- test/conf/force_nat_access.conf | 4 ++ test/conf/future_expired_stanza_access.conf | 4 ++ test/conf/invalid_expire_access.conf | 4 ++ test/test-fwknop.pl | 70 +++++++++++++++++++++ 21 files changed, 199 insertions(+), 56 deletions(-) create mode 100644 test/conf/force_nat_access.conf create mode 100644 test/conf/future_expired_stanza_access.conf create mode 100644 test/conf/invalid_expire_access.conf diff --git a/client/config_init.c b/client/config_init.c index 7a5ab727..f0cd41b7 100644 --- a/client/config_init.c +++ b/client/config_init.c @@ -240,7 +240,7 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) else if(CONF_VAR_IS(var, "SPA_SERVER_PORT")) { tmpint = atoi(val); - if(tmpint < 0 || tmpint > 65535) + if(tmpint < 0 || tmpint > MAX_PORT) return(-1); else options->spa_dst_port = tmpint; @@ -249,7 +249,7 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) else if(CONF_VAR_IS(var, "SPA_SOURCE_PORT")) { tmpint = atoi(val); - if(tmpint < 0 || tmpint > 65535) + if(tmpint < 0 || tmpint > MAX_PORT) return(-1); else options->spa_src_port = tmpint; @@ -277,7 +277,7 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) else if(strcasecmp(val, "resolve") == 0) options->resolve_ip_http = 1; else /* Assume IP address */ - strlcpy(options->allow_ip_str, val, MAX_IP_STR_LEN); + strlcpy(options->allow_ip_str, val, MAX_IPV4_STR_LEN); } /* Time Offset */ else if(CONF_VAR_IS(var, "TIME_OFFSET")) @@ -319,7 +319,7 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) /* Spoof Source IP */ else if(CONF_VAR_IS(var, "SPOOF_SOURCE_IP")) { - strlcpy(options->spoof_ip_src_str, val, MAX_IP_STR_LEN); + strlcpy(options->spoof_ip_src_str, val, MAX_IPV4_STR_LEN); } /* ACCESS request */ else if(CONF_VAR_IS(var, "ACCESS")) @@ -382,7 +382,7 @@ parse_rc_param(fko_cli_options_t *options, const char *var, char * val) else if(CONF_VAR_IS(var, "NAT_PORT")) { tmpint = atoi(val); - if(tmpint < 0 || tmpint > 65535) + if(tmpint < 0 || tmpint > MAX_PORT) return(-1); else options->nat_port = tmpint; @@ -673,13 +673,13 @@ config_init(fko_cli_options_t *options, int argc, char **argv) /* Reset the options index so we can run through them again. */ optind = 0; - + while ((cmd_arg = getopt_long(argc, argv, GETOPTS_OPTION_STRING, cmd_opts, &index)) != -1) { switch(cmd_arg) { case 'a': - strlcpy(options->allow_ip_str, optarg, MAX_IP_STR_LEN); + strlcpy(options->allow_ip_str, optarg, MAX_IPV4_STR_LEN); break; case 'A': strlcpy(options->access_str, optarg, MAX_LINE_LEN); @@ -740,7 +740,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) break; case 'p': options->spa_dst_port = atoi(optarg); - if (options->spa_dst_port < 0 || options->spa_dst_port > 65535) + if (options->spa_dst_port < 0 || options->spa_dst_port > MAX_PORT) { fprintf(stderr, "Unrecognized port: %s\n", optarg); exit(EXIT_FAILURE); @@ -754,7 +754,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) } break; case 'Q': - strlcpy(options->spoof_ip_src_str, optarg, MAX_IP_STR_LEN); + strlcpy(options->spoof_ip_src_str, optarg, MAX_IPV4_STR_LEN); break; case 'r': options->rand_port = 1; @@ -777,11 +777,11 @@ config_init(fko_cli_options_t *options, int argc, char **argv) options->show_last_command = 1; break; case 's': - strlcpy(options->allow_ip_str, "0.0.0.0", MAX_IP_STR_LEN); + strlcpy(options->allow_ip_str, "0.0.0.0", MAX_IPV4_STR_LEN); break; case 'S': options->spa_src_port = atoi(optarg); - if (options->spa_src_port < 0 || options->spa_src_port > 65535) + if (options->spa_src_port < 0 || options->spa_src_port > MAX_PORT) { fprintf(stderr, "Unrecognized port: %s\n", optarg); exit(EXIT_FAILURE); @@ -827,7 +827,7 @@ config_init(fko_cli_options_t *options, int argc, char **argv) break; case NAT_PORT: options->nat_port = atoi(optarg); - if (options->nat_port < 0 || options->nat_port > 65535) + if (options->nat_port < 0 || options->nat_port > MAX_PORT) { fprintf(stderr, "Unrecognized port: %s\n", optarg); exit(EXIT_FAILURE); diff --git a/client/fwknop_common.h b/client/fwknop_common.h index e0f3e302..5d7e8ef3 100644 --- a/client/fwknop_common.h +++ b/client/fwknop_common.h @@ -85,8 +85,8 @@ typedef struct fko_cli_options int run_last_command; int no_save_args; char spa_server_str[MAX_SERVER_STR_LEN]; /* may be a hostname */ - char allow_ip_str[MAX_IP_STR_LEN]; - char spoof_ip_src_str[MAX_IP_STR_LEN]; + char allow_ip_str[MAX_IPV4_STR_LEN]; + char spoof_ip_src_str[MAX_IPV4_STR_LEN]; char spoof_user[MAX_USERNAME_LEN]; int rand_port; char gpg_recipient_key[MAX_GPG_KEY_ID]; diff --git a/client/http_resolve_host.c b/client/http_resolve_host.c index f6afe61f..9282437d 100644 --- a/client/http_resolve_host.c +++ b/client/http_resolve_host.c @@ -78,7 +78,7 @@ parse_url(char *res_url, struct url* url) if(e_ndx != NULL) { port = atoi(e_ndx+1); - if(port < 1 || port > 65535) + if(port < 1 || port > MAX_PORT) { fprintf(stderr, "resolve-url port value is invalid.\n"); return(-1); @@ -251,7 +251,7 @@ resolve_ip_http(fko_cli_options_t *options) * Note: We are expecting the content to be just an IP address * (possibly followed by whitespace or other not-digit value). */ - for(i=0; i= 0 && o3 <= 255 && o4 >= 0 && o4 <= 255) { - strlcpy(options->allow_ip_str, ndx, MAX_IP_STR_LEN); + strlcpy(options->allow_ip_str, ndx, MAX_IPV4_STR_LEN); if(options->verbose) printf("Resolved external IP (via http://%s%s) as: %s\n", diff --git a/common/common.h b/common/common.h index 80d9277b..c063cfd2 100644 --- a/common/common.h +++ b/common/common.h @@ -104,8 +104,8 @@ enum { #define MAX_PORT 65535 #define MAX_PORT_STR_LEN 6 #define MAX_PROTO_STR_LEN 6 -#define MAX_IP_STR_LEN 16 -#define MIN_IP_STR_LEN 9 +#define MAX_IPV4_STR_LEN 16 +#define MIN_IPV4_STR_LEN 9 #define MAX_SERVER_STR_LEN 50 #define MAX_LINE_LEN 1024 diff --git a/doc/fwknop.man.asciidoc b/doc/fwknop.man.asciidoc index 57d8395e..f110d20c 100644 --- a/doc/fwknop.man.asciidoc +++ b/doc/fwknop.man.asciidoc @@ -162,7 +162,7 @@ SPA OPTIONS Specify IP address that should be permitted through the destination *fwknopd* server firewall (this IP is encrypted within the SPA packet itself). This is useful to prevent a MTIM attack where a SPA packet - can be intercepted enroute and sent from a different IP than the + can be intercepted en-route and sent from a different IP than the original. Hence, if the *fwknopd* server trusts the source address on the SPA packet IP header then the attacker gains access. The *-a* option puts the source address within the encrypted SPA @@ -359,7 +359,7 @@ commented out. It is up to the user to edit this file to meet their needs. The '.fwknoprc' file contains a default configuration area or stanza which holds global configuration directives that override the program defaults. -You can edit this file and create additonal 'named stanzas' that can be +You can edit this file and create additional 'named stanzas' that can be specified with the *-n* or *--named-config* option. Parameters defined in the named stanzas will override any matching 'default' stanza directives. Note that command-line options will still override any corresponding diff --git a/doc/fwknopd.man.asciidoc b/doc/fwknopd.man.asciidoc index f0e4a204..a4b86667 100644 --- a/doc/fwknopd.man.asciidoc +++ b/doc/fwknopd.man.asciidoc @@ -29,7 +29,7 @@ vulnerabilities (both 0-day and unpatched code) much more difficult. The main configuration for *fwknopd* is maintained within two files: 'fwknopd.conf' and 'access.conf'. The default location for these files is determined at package configuration (typically '@sysconfdir@/fwknop')The -configuration variables within these files are desribed below. +configuration variables within these files are described below. COMMAND-LINE OPTIONS @@ -183,7 +183,7 @@ See the 'fwknopd.conf' file for the full list and corresponding details. *ACCESS_EXPIRE_EPOCH* '':: Defines an expiration date for the access stanza as the epoch time, and is useful if a more accurate expiration time needs to be given than the day - resolution offered by the ACCESS_EXPIRE variable agove. All SPA packets + resolution offered by the ACCESS_EXPIRE variable above. All SPA packets that match an expired stanza will be ignored. This parameter is optional. *ENABLE_DIGEST_PERSISTENCE* '':: @@ -221,7 +221,7 @@ See the 'fwknopd.conf' file for the full list and corresponding details. when ``ENABLE_IPT_SNAT'' is set to ``Y'' and by default SNAT rules are built with the MASQUERADE target (since then the internal IP does not have to be defined here in the 'fwknopd.conf' file), but if you want - *fwknopd* to use the SNAT target, you mus also define an IP address with + *fwknopd* to use the SNAT target, you must also define an IP address with the ``SNAT_TRANSLATE_IP'' variable. *ENABLE_IPT_OUTPUT* '':: @@ -306,7 +306,7 @@ is granted to *fwknop* clients that have generated the appropriate encrypted message. The 'access.conf' variables described below provide the access directives -for the SPA packets with a source (or embeded request) IP that matches an +for the SPA packets with a source (or embedded request) IP that matches an address or network range defined by the ``SOURCE'' variable. All variables following ``SOURCE'' apply to the source 'stanza'. Each ``SOURCE'' directive starts a new stanza. @@ -368,6 +368,14 @@ directive starts a new stanza. to be used to automatically resolve the external address (if the client behind a NAT) or the client must know the external IP. +*FORCE_NAT*: ' ':: + For any valid SPA packet, force the requested connection to be NAT'd + through to the specified (usually internal) IP and port value. This is + useful if there are multiple internal systems running a service such as + SSHD, and you want to give transparent access to only one internal system + for each stanza in the access.conf file. This way, multiple external + users can each directly access only one internal system per SPA key. + *GPG_HOME_DIR*: '':: Define the path to the GnuPG directory to be used by the *fwknopd* server. If this keyword is not specified within 'access.conf' then @@ -442,7 +450,7 @@ are received. SEE ALSO -------- -fwknop(8), iptables(8), libfko docmentation. +fwknop(8), iptables(8), libfko documentation. AUTHOR diff --git a/server/access.c b/server/access.c index d7ebcc31..3633e885 100644 --- a/server/access.c +++ b/server/access.c @@ -80,11 +80,12 @@ add_acc_expire_time(fko_srv_options_t *opts, time_t *access_expire_time, const c memset(&tm, 0, sizeof(struct tm)); - if (sscanf(val, "%d/%d/%d", &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3) + if (sscanf(val, "%2d/%2d/%4d", &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3) { log_msg(LOG_ERR, - "Fatal invalid epoch seconds value for access stanza expiration time" + "Fatal: invalid date value '%s' (need MM/DD/YYYY) for access stanza expiration time", + val ); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } @@ -120,7 +121,8 @@ add_acc_expire_time_epoch(fko_srv_options_t *opts, time_t *access_expire_time, c if (errno == ERANGE || (errno != 0 && expire_time == 0)) { log_msg(LOG_ERR, - "Fatal invalid epoch seconds value for access stanza expiration time" + "Fatal: invalid epoch seconds value '%s' for access stanza expiration time", + val ); clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); } @@ -130,6 +132,34 @@ add_acc_expire_time_epoch(fko_srv_options_t *opts, time_t *access_expire_time, c return; } +static void +add_acc_force_nat(fko_srv_options_t *opts, acc_stanza_t *curr_acc, const char *val) +{ + char ip_str[MAX_IPV4_STR_LEN] = {0}; + + if (sscanf(val, "%15s %5u", ip_str, &curr_acc->force_nat_port) != 2) + { + + log_msg(LOG_ERR, + "Fatal: invalid FORCE_NAT arg '%s', need ", + val + ); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + if (curr_acc->force_nat_port > MAX_PORT) + { + log_msg(LOG_ERR, + "Fatal: invalid FORCE_NAT port '%d'", curr_acc->force_nat_port); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + + curr_acc->force_nat = 1; + add_acc_string(&(curr_acc->force_nat_ip), ip_str); + + return; +} + /* Take an IP or Subnet/Mask and convert it to mask for later * comparisons of incoming source IPs against this mask. */ @@ -137,7 +167,7 @@ static void add_source_mask(acc_stanza_t *acc, const char *ip) { char *ndx; - char ip_str[16] = {0}; + char ip_str[MAX_IPV4_STR_LEN] = {0}; uint32_t mask; struct in_addr in; @@ -523,6 +553,9 @@ free_acc_stanza_data(acc_stanza_t *acc) free_acc_port_list(acc->rport_list); } + if(acc->force_nat_ip != NULL) + free(acc->force_nat_ip); + if(acc->key != NULL) free(acc->key); @@ -915,6 +948,16 @@ parse_access_file(fko_srv_options_t *opts) { add_acc_expire_time_epoch(opts, &(curr_acc->access_expire_time), val); } + else if(CONF_VAR_IS(var, "FORCE_NAT")) + { + if(strncasecmp(opts->config[CONF_ENABLE_IPT_FORWARDING], "Y", 1) !=0 ) + { + fprintf(stderr, + "[*] FORCE_NAT requires ENABLE_IPT_FORWARDING to be enabled in fwknopd.conf\n"); + clean_exit(opts, NO_FW_CLEANUP, EXIT_FAILURE); + } + add_acc_force_nat(opts, curr_acc, val); + } else { fprintf(stderr, diff --git a/server/fw_util.h b/server/fw_util.h index b5afc1bd..1f520fee 100644 --- a/server/fw_util.h +++ b/server/fw_util.h @@ -63,7 +63,7 @@ void fw_initialize(const fko_srv_options_t *opts); int fw_cleanup(const fko_srv_options_t *opts); void check_firewall_rules(const fko_srv_options_t *opts); int fw_dump_rules(const fko_srv_options_t *opts); -int process_spa_request(const fko_srv_options_t *opts, spa_data_t *spdat); +int process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spdat); #endif /* FW_UTIL_H */ diff --git a/server/fw_util_ipf.c b/server/fw_util_ipf.c index 7233749a..37937aad 100644 --- a/server/fw_util_ipf.c +++ b/server/fw_util_ipf.c @@ -109,11 +109,11 @@ fw_cleanup(void) /* Rule Processing - Create an access request... */ int -process_spa_request(const fko_srv_options_t *opts, spa_data_t *spadat) +process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat) { /* TODO: Implement me */ - char nat_ip[16] = {0}; + char nat_ip[MAX_IPV4_STR_LEN] = {0}; char *ndx; unsigned int nat_port = 0;; diff --git a/server/fw_util_ipfw.c b/server/fw_util_ipfw.c index f82def08..6e2370e6 100644 --- a/server/fw_util_ipfw.c +++ b/server/fw_util_ipfw.c @@ -415,7 +415,7 @@ fw_cleanup(const fko_srv_options_t *opts) /* Rule Processing - Create an access request... */ int -process_spa_request(const fko_srv_options_t *opts, spa_data_t *spadat) +process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat) { unsigned short rule_num; diff --git a/server/fw_util_iptables.c b/server/fw_util_iptables.c index e6ccd841..a1a36ec3 100644 --- a/server/fw_util_iptables.c +++ b/server/fw_util_iptables.c @@ -479,9 +479,9 @@ fw_cleanup(const fko_srv_options_t *opts) /* Rule Processing - Create an access request... */ int -process_spa_request(const fko_srv_options_t *opts, spa_data_t *spadat) +process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat) { - char nat_ip[16] = {0}; + char nat_ip[MAX_IPV4_STR_LEN] = {0}; char snat_target[SNAT_TARGET_BUFSIZE] = {0}; char *ndx; @@ -525,8 +525,8 @@ process_spa_request(const fko_srv_options_t *opts, spa_data_t *spadat) /* 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) + if((spadat->message_type == FKO_ACCESS_MSG + || spadat->message_type == FKO_CLIENT_TIMEOUT_ACCESS_MSG) && !acc->force_nat) { /* Check to make sure that the jump rules exist for each @@ -578,7 +578,7 @@ process_spa_request(const fko_srv_options_t *opts, spa_data_t *spadat) in_chain->next_expire = exp_ts; } else - log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); + log_msg(LOG_ERR, "Error %i from cmd:'%s': %s", res, cmd_buf, err_buf); /* If we have to make an corresponding OUTPUT rule if out_chain target * is not NULL. @@ -631,19 +631,25 @@ process_spa_request(const fko_srv_options_t *opts, spa_data_t *spadat) 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 ) + || spadat->message_type == FKO_CLIENT_TIMEOUT_NAT_ACCESS_MSG + || acc->force_nat) { /* Parse out the NAT IP and Port components. */ - ndx = strchr(spadat->nat_access, ','); - if(ndx != NULL) + if(acc->force_nat) { - strlcpy(nat_ip, spadat->nat_access, (ndx-spadat->nat_access)+1); - nat_port = atoi(ndx+1); + strlcpy(nat_ip, acc->force_nat_ip, MAX_IPV4_STR_LEN); + nat_port = acc->force_nat_port; + } + else + { + 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 */ diff --git a/server/fw_util_pf.c b/server/fw_util_pf.c index 22e32d0a..8f100717 100644 --- a/server/fw_util_pf.c +++ b/server/fw_util_pf.c @@ -204,7 +204,7 @@ fw_cleanup(const fko_srv_options_t *opts) /* Rule Processing - Create an access request... */ int -process_spa_request(const fko_srv_options_t *opts, spa_data_t *spadat) +process_spa_request(const fko_srv_options_t *opts, const acc_stanza_t *acc, spa_data_t *spadat) { char new_rule[MAX_PF_NEW_RULE_LEN]; char write_cmd[CMD_BUFSIZE]; diff --git a/server/fwknopd.c b/server/fwknopd.c index 337ac0e9..5a780b39 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -282,7 +282,7 @@ main(int argc, char **argv) if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0) { if(atoi(opts.config[CONF_TCPSERV_PORT]) <= 0 - || atoi(opts.config[CONF_TCPSERV_PORT]) > 65535) + || atoi(opts.config[CONF_TCPSERV_PORT]) > MAX_PORT) { log_msg(LOG_WARNING, "WARNING: ENABLE_TCP_SERVER is set, but TCPSERV_PORT is not valid. TCP server not started!" diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 817891eb..4fe7ec4f 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -282,6 +282,10 @@ typedef struct acc_stanza acc_string_list_t *gpg_remote_id_list; time_t access_expire_time; int expired; + unsigned char force_nat; + char *force_nat_ip; + char *force_nat_proto; + unsigned int force_nat_port; struct acc_stanza *next; } acc_stanza_t; @@ -386,8 +390,8 @@ typedef struct spa_data char *version; short message_type; char *spa_message; - char spa_message_src_ip[MAX_IP_STR_LEN]; - char pkt_source_ip[MAX_IP_STR_LEN]; + char spa_message_src_ip[MAX_IPV4_STR_LEN]; + char pkt_source_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 ac4e5f18..c625e4d1 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -616,7 +616,7 @@ incoming_spa(fko_srv_options_t *opts) * access stanza loop (first valid access stanza stops us looking * for others). */ - process_spa_request(opts, &spadat); + process_spa_request(opts, acc, &spadat); if(ctx != NULL) fko_destroy(ctx); break; diff --git a/server/tcp_server.c b/server/tcp_server.c index 1cab2bc2..77c0ac32 100644 --- a/server/tcp_server.c +++ b/server/tcp_server.c @@ -60,7 +60,7 @@ run_tcp_server(fko_srv_options_t *opts) fd_set sfd_set; struct sockaddr_in saddr, caddr; struct timeval tv; - char sipbuf[MAX_IP_STR_LEN]; + char sipbuf[MAX_IPV4_STR_LEN]; unsigned short port = atoi(opts->config[CONF_TCPSERV_PORT]); @@ -196,8 +196,8 @@ run_tcp_server(fko_srv_options_t *opts) if(opts->verbose) { - memset(sipbuf, 0x0, MAX_IP_STR_LEN); - inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IP_STR_LEN); + memset(sipbuf, 0x0, MAX_IPV4_STR_LEN); + inet_ntop(AF_INET, &(caddr.sin_addr.s_addr), sipbuf, MAX_IPV4_STR_LEN); log_msg(LOG_INFO, "tcp_server: Got TCP connection from %s.", sipbuf); } diff --git a/test/conf/expired_stanza_access.conf b/test/conf/expired_stanza_access.conf index a928005a..8678550b 100644 --- a/test/conf/expired_stanza_access.conf +++ b/test/conf/expired_stanza_access.conf @@ -1,4 +1,4 @@ SOURCE: ANY; KEY: fwknoptest; FW_ACCESS_TIMEOUT: 3; -ACCESS_EXPIRE: 3/10/1999; ### very old +ACCESS_EXPIRE: 3/10/01; ### very old diff --git a/test/conf/force_nat_access.conf b/test/conf/force_nat_access.conf new file mode 100644 index 00000000..b2f18b09 --- /dev/null +++ b/test/conf/force_nat_access.conf @@ -0,0 +1,4 @@ +SOURCE: ANY; +KEY: fwknoptest; +FW_ACCESS_TIMEOUT: 3; +FORCE_NAT: 192.168.1.123 22; diff --git a/test/conf/future_expired_stanza_access.conf b/test/conf/future_expired_stanza_access.conf new file mode 100644 index 00000000..c39675b0 --- /dev/null +++ b/test/conf/future_expired_stanza_access.conf @@ -0,0 +1,4 @@ +SOURCE: ANY; +KEY: fwknoptest; +FW_ACCESS_TIMEOUT: 3; +ACCESS_EXPIRE: 3/10/2500; ### way in the future diff --git a/test/conf/invalid_expire_access.conf b/test/conf/invalid_expire_access.conf new file mode 100644 index 00000000..2dd3d243 --- /dev/null +++ b/test/conf/invalid_expire_access.conf @@ -0,0 +1,4 @@ +SOURCE: ANY; +KEY: fwknoptest; +FW_ACCESS_TIMEOUT: 3; +ACCESS_EXPIRE: 3-10-01; ### / separators required diff --git a/test/test-fwknop.pl b/test/test-fwknop.pl index 516b5e4f..0be4cce4 100755 --- a/test/test-fwknop.pl +++ b/test/test-fwknop.pl @@ -23,7 +23,10 @@ my $nat_conf = "$conf_dir/nat_fwknopd.conf"; my $default_conf = "$conf_dir/default_fwknopd.conf"; my $default_access_conf = "$conf_dir/default_access.conf"; my $expired_access_conf = "$conf_dir/expired_stanza_access.conf"; +my $future_expired_access_conf = "$conf_dir/future_expired_stanza_access.conf"; my $expired_epoch_access_conf = "$conf_dir/expired_epoch_stanza_access.conf"; +my $invalid_expire_access_conf = "$conf_dir/invalid_expire_access.conf"; +my $force_nat_access_conf = "$conf_dir/force_nat_access.conf"; my $gpg_access_conf = "$conf_dir/gpg_access.conf"; my $default_digest_file = "$run_dir/digest.cache"; my $default_pid_file = "$run_dir/fwknopd.pid"; @@ -53,6 +56,7 @@ my $gpg_client_key = '6A3FAD56'; my $loopback_ip = '127.0.0.1'; my $fake_ip = '127.0.0.2'; my $internal_nat_host = '192.168.1.2'; +my $force_nat_host = '192.168.1.123'; my $default_spa_port = 62201; my $non_std_spa_port = 12345; @@ -626,6 +630,20 @@ my @tests = ( 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, 'fatal' => $NO }, + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => 'invalid expire date (tcp/22 ssh)', + 'err_msg' => 'SPA packet accepted', + 'function' => \&spa_cycle, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopdCmd -c $default_conf -a $invalid_expire_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'server_positive_output_matches' => [qr/invalid\sdate\svalue/], + 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, + 'fatal' => $NO + }, { 'category' => 'Rijndael SPA', 'subcategory' => 'client+server', @@ -640,6 +658,20 @@ my @tests = ( 'fw_rule_created' => $REQUIRE_NO_NEW_RULE, 'fatal' => $NO }, + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => 'future expired stanza (tcp/22 ssh)', + 'err_msg' => 'SPA packet not accepted', + 'function' => \&spa_cycle, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopdCmd -c $default_conf -a $future_expired_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, { 'category' => 'Rijndael SPA', @@ -866,6 +898,25 @@ my @tests = ( 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . "$fwknopdCmd -c $nat_conf -a $open_ports_access_conf " . "-d $default_digest_file -p $default_pid_file $intf_str", + 'server_positive_output_matches' => [qr/to\:$internal_nat_host\:22/i], + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'server_conf' => $nat_conf, + 'fatal' => $NO + }, + + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => "force NAT $force_nat_host (tcp/22 ssh)", + 'err_msg' => "could not complete NAT SPA cycle", + 'function' => \&spa_cycle, + 'cmdline' => $default_client_args, + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopdCmd -c $nat_conf -a $force_nat_access_conf " . + "-d $default_digest_file -p $default_pid_file $intf_str", + 'server_positive_output_matches' => [qr/to\:$force_nat_host\:22/i], + 'server_negative_output_matches' => [qr/to\:$internal_nat_host\:22/i], 'fw_rule_created' => $NEW_RULE_REQUIRED, 'fw_rule_removed' => $NEW_RULE_REMOVED, 'server_conf' => $nat_conf, @@ -932,6 +983,22 @@ my @tests = ( 'fw_rule_removed' => $NEW_RULE_REMOVED, 'fatal' => $NO }, + + { + 'category' => 'Rijndael SPA', + 'subcategory' => 'client+server', + 'detail' => 'random SPA port (tcp/22 ssh)', + 'err_msg' => 'could not complete SPA cycle', + 'function' => \&spa_cycle, + 'cmdline' => "$default_client_args -r", + 'fwknopd_cmdline' => "LD_LIBRARY_PATH=$lib_dir $valgrind_str " . + "$fwknopdCmd $default_server_conf_args $intf_str " . + qq|-P "udp"|, + 'fw_rule_created' => $NEW_RULE_REQUIRED, + 'fw_rule_removed' => $NEW_RULE_REMOVED, + 'fatal' => $NO + }, + { 'category' => 'Rijndael SPA', 'subcategory' => 'client+server', @@ -2371,6 +2438,9 @@ sub init() { $multi_stanzas_access_conf, $expired_access_conf, $expired_epoch_access_conf, + $future_expired_access_conf, + $invalid_expire_access_conf, + $force_nat_access_conf, ) { die "[*] $file does not exist" unless -e $file; }