From aad2daadbfe4285fb9ece3153d7517ce9041f8d0 Mon Sep 17 00:00:00 2001 From: Damien Stuart Date: Mon, 17 May 2010 01:27:26 +0000 Subject: [PATCH] First cut at creating access rules and removing them when they expire (not sure I like this implementation but it is a start). git-svn-id: file:///home/mbr/svn/fwknop/trunk@214 510a4753-2344-4c79-9c09-4d669213fbeb --- server/access.c | 8 +- server/access.h | 6 +- server/extcmd.c | 2 + server/fw_util.c | 283 +++++++++++++++++++++++++++++++++++++--- server/fw_util.h | 18 +++ server/fwknopd.c | 7 +- server/fwknopd_common.h | 45 +++++-- server/incoming_spa.c | 208 ++++++++++++++++------------- server/pcap_capture.c | 4 +- 9 files changed, 447 insertions(+), 134 deletions(-) diff --git a/server/access.c b/server/access.c index 417cf8c9..495de7b4 100644 --- a/server/access.c +++ b/server/access.c @@ -308,7 +308,7 @@ add_string_list_ent(acc_string_list_t **stlist, char *str_str) /* Expand a proto/port access string to a list of access proto-port struct. */ -static acc_port_list_t* +void expand_acc_port_list(acc_port_list_t **plist, char *plist_str) { char *ndx, *start; @@ -333,7 +333,7 @@ expand_acc_port_list(acc_port_list_t **plist, char *plist_str) /* Expand a comma-separated string into a simple acc_string_list. */ -static acc_string_list_t* +static void expand_acc_string_list(acc_string_list_t **stlist, char *stlist_str) { char *ndx, *start; @@ -374,7 +374,7 @@ free_acc_source_list(acc_int_list_t *sle) /* Free a port_list */ -static void +void free_acc_port_list(acc_port_list_t *ple) { acc_port_list_t *last_ple; @@ -616,7 +616,7 @@ parse_access_file(fko_srv_options_t *opts) acc_stanza_t *curr_acc = NULL; /* First see if the access file exists. If it doesn't, complain - * and go on with program defaults. + * and bail. */ if(stat(opts->config[CONF_ACCESS_FILE], &st) != 0) { diff --git a/server/access.h b/server/access.h index 3f2edd9f..49367326 100644 --- a/server/access.h +++ b/server/access.h @@ -26,8 +26,8 @@ #ifndef ACCESS_H #define ACCESS_H -#define PROTO_TCP 0 -#define PROTO_UDP 1 +#define PROTO_TCP 6 +#define PROTO_UDP 17 /* Function Prototypes */ @@ -35,6 +35,8 @@ void parse_access_file(fko_srv_options_t *opts); acc_stanza_t* acc_check_source(fko_srv_options_t *opts, uint32_t ip); int acc_check_port_access(acc_stanza_t *acc, char *port_str); void dump_access_list(fko_srv_options_t *opts); +void expand_acc_port_list(acc_port_list_t **plist, char *plist_str); +void free_acc_port_list(acc_port_list_t *plist); #endif /* ACCESS_H */ diff --git a/server/extcmd.c b/server/extcmd.c index e43d514a..16f158bf 100644 --- a/server/extcmd.c +++ b/server/extcmd.c @@ -49,6 +49,8 @@ set_nonblock(int fd) int run_extcmd(char *cmd, char *so_buf, char *se_buf, size_t so_buf_sz, size_t se_buf_sz, int *status) { +//--DSS temp +//return(0); pid_t pid; struct timeval tv; diff --git a/server/fw_util.c b/server/fw_util.c index dfc4137f..99aa98c2 100644 --- a/server/fw_util.c +++ b/server/fw_util.c @@ -28,13 +28,14 @@ #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 void parse_extcmd_error(int retval, int status, char *se_buf) { - char errmsg[256]; + char errmsg[CMD_BUFSIZE]; char *emptr = errmsg; if(retval < 0) @@ -83,9 +84,9 @@ static int jump_rule_exists(int chain_num) { int num, x, pos = 0; - char cmd_buf[256]; - char target[256]; - char line_buf[256] = {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, @@ -103,7 +104,7 @@ jump_rule_exists(int chain_num) return(-1); } - while((fgets(line_buf, 255, ipt)) != NULL) + while((fgets(line_buf, CMD_BUFSIZE-1, ipt)) != NULL) { /* Get past comments and empty lines (note: we only look at the * first character. @@ -133,8 +134,8 @@ delete_all_chains(void) { int i, pos, res, status; int jump_rule_num; - char cmd_buf[256]; - char err[256]; + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; for(i=0; i<(NUM_FWKNOP_CHAIN_TYPES-1); i++) { @@ -146,7 +147,7 @@ delete_all_chains(void) */ if((jump_rule_num = jump_rule_exists(i)) > 0) { - sprintf(cmd_buf, "%s " IPT_DEL_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_DEL_RULE_ARGS, fwc.fw_command, fwc.chain[i].table, fwc.chain[i].from_chain, @@ -154,15 +155,17 @@ delete_all_chains(void) ); //printf("CMD: '%s'\n", cmd_buf); - res = run_extcmd(cmd_buf, NULL, err, 0, 256, &status); + res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status); /* Expect full success on this */ if(! EXTCMD_IS_SUCCESS(res)) parse_extcmd_error(res, status, err); } + memset(cmd_buf, 0x0, CMD_BUFSIZE); + /* Now flush and remove the chain. */ - sprintf(cmd_buf, + 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, @@ -173,7 +176,7 @@ delete_all_chains(void) ); //printf("CMD: '%s'\n", cmd_buf); - res = run_extcmd(cmd_buf, NULL, err, 0, 256, &status); + res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status); /* Expect full success on this */ if(! EXTCMD_IS_SUCCESS(res)) parse_extcmd_error(res, status, err); @@ -187,8 +190,8 @@ create_fw_chains(void) { int i; int res, status, got_err = 0; - char cmd_buf[256]; - char err[256]; + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; for(i=0; i<(NUM_FWKNOP_CHAIN_TYPES-1); i++) { @@ -197,14 +200,14 @@ create_fw_chains(void) /* Create the custom chain. */ - sprintf(cmd_buf, "%s " IPT_NEW_CHAIN_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_NEW_CHAIN_ARGS, fwc.fw_command, fwc.chain[i].table, fwc.chain[i].to_chain ); //printf("CMD: '%s'\n", cmd_buf); - res = run_extcmd(cmd_buf, NULL, err, 0, 256, &status); + res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status); /* Expect full success on this */ if(! EXTCMD_IS_SUCCESS(res)) { @@ -212,9 +215,11 @@ create_fw_chains(void) got_err++; } + memset(cmd_buf, 0x0, CMD_BUFSIZE); + /* Then create the jump rule to that chain. */ - sprintf(cmd_buf, "%s " IPT_ADD_JUMP_RULE_ARGS, + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_JUMP_RULE_ARGS, fwc.fw_command, fwc.chain[i].table, fwc.chain[i].from_chain, @@ -223,7 +228,7 @@ create_fw_chains(void) ); //printf("CMD: '%s'\n", cmd_buf); - res = run_extcmd(cmd_buf, NULL, err, 0, 256, &status); + res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status); /* Expect full success on this */ if(! EXTCMD_IS_SUCCESS(res)) { @@ -374,4 +379,248 @@ fw_cleanup(void) delete_all_chains(); } +int +process_access_request(fko_srv_options_t *opts, spa_data_t *spadat) +{ + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + acc_port_list_t *port_list = NULL; + acc_port_list_t *ple; + + unsigned int cproto; + unsigned int cport; + + struct fw_chain *chain = &(opts->fw_config->chain[IPT_INPUT_ACCESS]); + + int status, res; + time_t now, exp_ts; + + /* Parse and expand our access message. + */ + expand_acc_port_list(&port_list, spadat->spa_message_remain); + + /* Create an access command for each proto/port for the source ip. + */ + ple = port_list; + while(ple != NULL) + { + time(&now); + exp_ts = now + spadat->fw_access_timeout; + + snprintf(cmd_buf, CMD_BUFSIZE-1, "%s " IPT_ADD_RULE_ARGS, + opts->fw_config->fw_command, + chain->table, + chain->to_chain, + ple->proto, + spadat->use_src_ip, + ple->port, + exp_ts, + chain->target + ); + +//--DSS tmp +//fprintf(stderr, "ADD CMD: %s", cmd_buf); + res = run_extcmd(cmd_buf, NULL, err, 0, CMD_BUFSIZE, &status); + if(EXTCMD_IS_SUCCESS(res)) + { + log_msg(LOG_INFO, "Added Rule to %s for %s, %s expires at %u", + chain->to_chain, spadat->use_src_ip, + spadat->spa_message_remain, exp_ts + ); + + chain->active_rules++; + + /* Reset the next expected expire time for this chain if it + * is warranted. + */ + if(chain->next_expire < now || exp_ts < chain->next_expire) + chain->next_expire = exp_ts; + } + else + parse_extcmd_error(res, status, err); + + ple = ple->next; + } + + + /* Done with the port list. + */ + free_acc_port_list(port_list); + + return(res); +} + +void +check_firewall_rules(fko_srv_options_t *opts) +{ + char cmd_buf[CMD_BUFSIZE] = {0}; + char err[CMD_BUFSIZE] = {0}; + char cmd_out[4096]; + char exp_str[12]; + char rule_num_str[6]; + char *ndx, *rn_start, *rn_end, *tmp_mark; + + int i, res, status, rn_offset; + time_t now, rule_exp, min_exp; + + 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_CHAIN_TYPES; i++) + { + /* Just in case we somehow lose track and fall out-of-whack. + */ + if(ch[i].active_rules < 0) + ch[i].active_rules = 0; + + /* If there are now 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; + +//fprintf(stderr, "CHAIN: %i, active_rules: %i, next_exp: %u, Now: %u\n", +// i, ch[i].active_rules, ch[i].next_expire, now); + + /* 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 "\n", + opts->fw_config->fw_command, + ch[i].table, + ch[i].to_chain + ); + + memset(cmd_out, 0x0, 4096); + + res = run_extcmd(cmd_buf, cmd_out, err, 4096, CMD_BUFSIZE, &status); + if(!EXTCMD_IS_SUCCESS(res)) + { + parse_extcmd_error(res, status, err); + continue; + } + + //fprintf(stderr, "RULES LIST:\n%s\n", cmd_out); + + ndx = strstr(cmd_out, "_exp_"); + if(ndx == NULL) + { + /* we did not find an expected rule. + */ + log_msg(LOG_ERR|LOG_STDERR, + "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|LOG_STDERR, + "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|LOG_STDERR, + "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, NULL, err, 0, CMD_BUFSIZE, &status); + 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 + parse_extcmd_error(res, status, 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 + ch[i].next_expire = min_exp; + } +} + /***EOF***/ diff --git a/server/fw_util.h b/server/fw_util.h index ea74672d..d59cf007 100644 --- a/server/fw_util.h +++ b/server/fw_util.h @@ -26,10 +26,28 @@ #ifndef FW_UTIL_H #define FW_UTIL_H +#define CMD_BUFSIZE 256 +#define MAX_FW_COMMAND_ARGS_LEN 256 + +/* iptables command args +*/ +//#define IPT_ADD_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -j %s" +#define IPT_ADD_RULE_ARGS "-t %s -A %s -p %i -s %s --dport %i -m comment --comment _exp_%u -j %s" +#define IPT_DEL_RULE_ARGS "-t %s -D %s %i" +#define IPT_NEW_CHAIN_ARGS "-t %s -N %s" +#define IPT_FLUSH_CHAIN_ARGS "-t %s -F %s" +#define IPT_DEL_CHAIN_ARGS "-t %s -X %s" +#define IPT_ADD_JUMP_RULE_ARGS "-t %s -I %s %i -j %s" +#define IPT_LIST_RULES_ARGS "-t %s -L %s --line-numbers -n" + +#define DEF_FW_ACCESS_TIMEOUT 60 + /* Function prototypes */ void fw_initialize(fko_srv_options_t *opts); void fw_cleanup(void); +int process_access_request(fko_srv_options_t *opts, spa_data_t *spdat); +void check_firewall_rules(fko_srv_options_t *opts); #endif /* FW_UTIL_H */ diff --git a/server/fwknopd.c b/server/fwknopd.c index 7ba80483..bb932218 100644 --- a/server/fwknopd.c +++ b/server/fwknopd.c @@ -172,7 +172,7 @@ main(int argc, char **argv) } /* If we are a new process (just being started), proceed with normal - * startp. Otherwise, we are here as a result of a signal sent to an + * start-up. Otherwise, we are here as a result of a signal sent to an * existing process and we want to restart. */ if(get_running_pid(&opts) != getpid()) @@ -581,10 +581,9 @@ get_running_pid(fko_srv_options_t *opts) if(op_fd > 0) { - if (read(op_fd, buf, 6) == 6) - { + if (read(op_fd, buf, 6) > 0) rpid = (pid_t)atoi(buf); - } + close(op_fd); } diff --git a/server/fwknopd_common.h b/server/fwknopd_common.h index 721eaaad..749eafb8 100644 --- a/server/fwknopd_common.h +++ b/server/fwknopd_common.h @@ -85,7 +85,7 @@ enum { }; /* SPA message handling status code - */ +*/ enum { SPA_MSG_SUCCESS = 0, SPA_MSG_BAD_DATA, @@ -99,6 +99,15 @@ enum { SPA_MSG_ERROR }; +/* Firewall rule processing error codes +*/ +enum { + FW_RULE_SUCCESS = 0, + FW_RULE_ADD_ERROR = 0x1000, + FW_RULE_DELETE_ERROR, + FW_RULE_UNKNOWN_ERROR +}; + /* Configuration file parameter tags. * This will correspond to entries in the configuration parameters * array. @@ -322,18 +331,6 @@ typedef struct acc_stanza #define MAX_CHAIN_NAME_LEN 32 #define MAX_TARGET_NAME_LEN 32 -#define MAX_FW_COMMAND_ARGS_LEN 256 - -/* iptables command args -*/ -#define IPT_ADD_RULE_ARGS "-t %s -I %s %i -p %s -s %s -d %s --dport %s -j %s" -#define IPT_DEL_RULE_ARGS "-t %s -D %s %i" -#define IPT_NEW_CHAIN_ARGS "-t %s -N %s" -#define IPT_FLUSH_CHAIN_ARGS "-t %s -F %s" -#define IPT_DEL_CHAIN_ARGS "-t %s -X %s" -#define IPT_ADD_JUMP_RULE_ARGS "-t %s -I %s %i -j %s" -#define IPT_LIST_RULES_ARGS " -t %s -L %s --line-numbers -n" - /* Fwknop custom chain types */ enum { @@ -370,6 +367,8 @@ struct fw_chain { int jump_rule_pos; char to_chain[MAX_CHAIN_NAME_LEN]; int rule_pos; + int active_rules; + time_t next_expire; }; /* Based on the fw_chain fields (not counting type) @@ -381,7 +380,6 @@ struct fw_config { char fw_command[MAX_PATH_LEN]; }; - /* SPA Packet info struct. */ typedef struct spa_pkt_info @@ -391,6 +389,25 @@ typedef struct spa_pkt_info unsigned char packet_data[MAX_SPA_PACKET_LEN+1]; } spa_pkt_info_t; +/* Struct for (processed and verified) SPA data used by the server. +*/ +typedef struct spa_data +{ + char *username; + time_t timestamp; + char *version; + short message_type; + char *spa_message; + char spa_message_src_ip[16]; + char pkt_source_ip[16]; + char spa_message_remain[1024]; /* --DSS arbitrary bounds */ + char *nat_access; + char *server_auth; + unsigned int client_timeout; + unsigned int fw_access_timeout; + char *use_src_ip; +} spa_data_t; + /* fwknopd server configuration parameters and values */ typedef struct fko_srv_options diff --git a/server/incoming_spa.c b/server/incoming_spa.c index 5bdbf72a..b182bebf 100644 --- a/server/incoming_spa.c +++ b/server/incoming_spa.c @@ -28,6 +28,48 @@ #include "access.h" #include "log_msg.h" +/* Popluate a spa_data struct from an initialized (and populated) FKO context. +*/ +int +get_spa_data_fields(fko_ctx_t ctx, spa_data_t *spdat) +{ + int res = FKO_SUCCESS; + + res = fko_get_username(ctx, &(spdat->username)); + if(res != FKO_SUCCESS) + return(res); + + res = fko_get_timestamp(ctx, &(spdat->timestamp)); + if(res != FKO_SUCCESS) + return(res); + + res = fko_get_version(ctx, &(spdat->version)); + if(res != FKO_SUCCESS) + return(res); + + res = fko_get_spa_message_type(ctx, &(spdat->message_type)); + if(res != FKO_SUCCESS) + return(res); + + res = fko_get_spa_message(ctx, &(spdat->spa_message)); + if(res != FKO_SUCCESS) + return(res); + + res = fko_get_spa_nat_access(ctx, &(spdat->nat_access)); + if(res != FKO_SUCCESS) + return(res); + + res = fko_get_spa_server_auth(ctx, &(spdat->server_auth)); + if(res != FKO_SUCCESS) + return(res); + + res = fko_get_spa_client_timeout(ctx, &(spdat->client_timeout)); + if(res != FKO_SUCCESS) + return(res); + + return(res); +} + /* Process the SPA packet data */ int @@ -39,32 +81,29 @@ incoming_spa(fko_srv_options_t *opts) fko_ctx_t ctx = NULL; char *spa_ip_demark; - char spa_msg_src_ip[16]; - char spa_msg_remain[1024]; /* --DSS should not have arbitrary limit */ time_t now_ts; int res, ts_diff, enc_type; - int got_spa_error = 0; spa_pkt_info_t *spa_pkt = &(opts->spa_pkt); - /* SPA data fields we will want to pull: + /* This will hold our pertinent SPA data. */ - time_t spa_ts; - short spa_msg_type; - char *spa_username; - char *spa_msg; - char *spa_nat_access; - int spa_client_timeout; + spa_data_t spadat; /* Get the access.conf data for the stanza that matches this incoming * source IP address. */ acc_stanza_t *acc = acc_check_source(opts, spa_pkt->packet_src_ip); + inet_ntop(AF_INET, &(spa_pkt->packet_src_ip), + spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip)); + + log_msg(LOG_INFO, "SPA packet from IP: %s received.", spadat.pkt_source_ip); + if(acc == NULL) { log_msg(LOG_WARNING|LOG_STDERR, - "No access data found for source IP: %u", spa_pkt->packet_src_ip + "No access data found for source IP: %s", spadat.pkt_source_ip ); return(SPA_MSG_ACCESS_DENIED); @@ -76,7 +115,7 @@ incoming_spa(fko_srv_options_t *opts) return(SPA_MSG_BAD_DATA); /* --DSS temp */ -fprintf(stderr, "SPA Packet: '%s'\n", spa_pkt->packet_data); +//fprintf(stderr, "SPA Packet: '%s'\n", spa_pkt->packet_data); /* --DSS temp */ /* Reset the packet data length to 0. This our indicator to the rest of @@ -127,7 +166,7 @@ fprintf(stderr, "SPA Packet: '%s'\n", spa_pkt->packet_data); if(acc->gpg_decrypt_id != NULL) fko_set_gpg_recipient(ctx, acc->gpg_decrypt_id); - /* If REMOTE_ID is set validate the check the signer. Otherwise, + /* If REMOTE_ID is set, validate and check the signer. Otherwise, * skip and ignore verify errors. * * TODO: At present we are not checking signatures. @@ -180,33 +219,45 @@ fprintf(stderr, "SPA Packet: '%s'\n", spa_pkt->packet_data); goto clean_and_bail; } + /* At this point, we assume the SPA data is valid. Now we need to see + * if it meets our access criteria. + */ /* --DSS temp */ -fprintf(stderr, "Decode res = %i\n", res); -display_ctx(ctx); +//fprintf(stderr, "Decode res = %i\n", res); +//display_ctx(ctx); /* --DSS temp */ + /* Check for replays if so configured. + */ if(strncasecmp(opts->config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0) { res = replay_check(opts, ctx); - if(res != SPA_MSG_SUCCESS) + if(res != 0) /* non-zero means we have seen this packet before. */ goto clean_and_bail; } + /* Populate our spa data struct for future reference. + */ + res = get_spa_data_fields(ctx, &spadat); + + spadat.fw_access_timeout = (acc->fw_access_timeout > 0) + ? acc->fw_access_timeout : DEF_FW_ACCESS_TIMEOUT; + + if(res != FKO_SUCCESS) + { + log_msg(LOG_ERR|LOG_STDERR, "Unexpected error pulling SPA data from the context: %s", + fko_errstr(res)); + res = SPA_MSG_ERROR; + goto clean_and_bail; + } + /* Check packet age if so configured. */ if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0) { - if(fko_get_timestamp(ctx, &spa_ts) != FKO_SUCCESS) - { - log_msg(LOG_WARNING|LOG_STDERR, "Error getting SPA timestamp: %s", - fko_errstr(res)); - res = SPA_MSG_ERROR; - goto clean_and_bail; - } - time(&now_ts); - ts_diff = now_ts - spa_ts; + ts_diff = now_ts - spadat.timestamp; if(ts_diff > atoi(opts->config[CONF_MAX_SPA_PACKET_AGE])) { @@ -217,26 +268,11 @@ display_ctx(ctx); } } - /* Ok, we can pull the rest of the spa data we are interested in. - */ - if(fko_get_spa_message_type(ctx, &spa_msg_type) != FKO_SUCCESS) - { - log_msg(LOG_WARNING|LOG_STDERR, "Error getting SPA message type: %s", - fko_errstr(res)); - got_spa_error++; - } - if(fko_get_spa_message(ctx, &spa_msg) != FKO_SUCCESS) - { - log_msg(LOG_WARNING|LOG_STDERR, "Error getting SPA message string: %s", - fko_errstr(res)); - got_spa_error++; - } - /* At this point, we have enough to check the embedded (or packet source) * IP address against the defined access rights. We start by splitting * the spa msg source IP from the remainder of the message. */ - spa_ip_demark = strchr(spa_msg, ','); + spa_ip_demark = strchr(spadat.spa_message, ','); if(spa_ip_demark == NULL) { log_msg(LOG_WARNING|LOG_STDERR, "Error parsing SPA message string: %s", @@ -245,68 +281,47 @@ display_ctx(ctx); goto clean_and_bail; } - strlcpy(spa_msg_src_ip, spa_msg, (spa_ip_demark-spa_msg)+1); - strlcpy(spa_msg_remain, spa_ip_demark+1, 1024); + strlcpy(spadat.spa_message_src_ip, spadat.spa_message, (spa_ip_demark - spadat.spa_message) + 1); + strlcpy(spadat.spa_message_remain, spa_ip_demark+1, 1024); /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it * is allowed. */ - if((strcmp(spa_msg_src_ip, "0.0.0.0") == 0) && acc->require_source_address) + if(strcmp(spadat.spa_message_src_ip, "0.0.0.0") == 0) { - log_msg(LOG_WARNING|LOG_STDERR, - "Got 0.0.0.0 when valid source IP was required." - ); - res = SPA_MSG_ACCESS_DENIED; - goto clean_and_bail; + if(acc->require_source_address) + { + log_msg(LOG_WARNING|LOG_STDERR, + "Got 0.0.0.0 when valid source IP was required." + ); + res = SPA_MSG_ACCESS_DENIED; + goto clean_and_bail; + } + + spadat.use_src_ip = spadat.pkt_source_ip; } + else + spadat.use_src_ip = spadat.spa_message_src_ip; /* If REQUIRE_USERNAME is set, make sure the username in this SPA data * matches. */ if(acc->require_username != NULL) { - if(fko_get_username(ctx, &spa_username) != FKO_SUCCESS) - { - log_msg(LOG_WARNING|LOG_STDERR, "Error getting SPA username string: %s", - fko_errstr(res)); - got_spa_error++; - } - - if(strcmp(spa_username, acc->require_username) != 0) + if(strcmp(spadat.username, acc->require_username) != 0) { log_msg(LOG_WARNING|LOG_STDERR, "Username in SPA data (%s) does not match required username: %s", - spa_username, acc->require_username + spadat.username, acc->require_username ); res = SPA_MSG_ACCESS_DENIED; goto clean_and_bail; } } - /* Get the rest of our SPA data fields. - */ - if(fko_get_spa_nat_access(ctx, &spa_nat_access) != FKO_SUCCESS) - { - log_msg(LOG_WARNING|LOG_STDERR, "Error getting SPA nat access string: %s", - fko_errstr(res)); - got_spa_error++; - } - if(fko_get_spa_client_timeout(ctx, &spa_client_timeout) != FKO_SUCCESS) - { - log_msg(LOG_WARNING|LOG_STDERR, "Error getting SPA client_timeout: %s", - fko_errstr(res)); - got_spa_error++; - } - - if(got_spa_error > 0) - { - res = SPA_MSG_ERROR; - goto clean_and_bail; - } - /* Take action based on SPA message type. */ - switch(spa_msg_type) + switch(spadat.message_type) { /* Command messages. */ @@ -314,7 +329,7 @@ display_ctx(ctx); if(!acc->enable_cmd_exec) { log_msg(LOG_WARNING|LOG_STDERR, - "SPA Command message are not yet allowed or supported." + "SPA Command message are not allowed in the current configuration." ); res = SPA_MSG_ACCESS_DENIED; } @@ -356,17 +371,28 @@ display_ctx(ctx); case FKO_CLIENT_TIMEOUT_ACCESS_MSG: /* Check access against restrict_ports and open_ports. */ - res = acc_check_port_access(acc, spa_msg_remain); + res = acc_check_port_access(acc, spadat.spa_message_remain); - // --DSS temp - log_msg(LOG_WARNING|LOG_STDERR, - "<<<< This SPA access msg would be %s >>>>", - res ? "allowed":"DENIED due to port restictions" - ); - - res = SPA_MSG_NOT_SUPPORTED; - - /* --DSS TODO: Finish Me */ + if(!res) + { + log_msg(LOG_WARNING|LOG_STDERR, + "One or more requested protocol/ports was denied per access.conf." + ); + res = SPA_MSG_ACCESS_DENIED; + } + else + { + /* Process the access message. + */ + /* --DSS temp + log_msg(LOG_WARNING|LOG_STDERR, + "<<<< This SPA access msg would be %s >>>>", + res ? "allowed":"DENIED due to port restictions" + ); + res = SPA_MSG_NOT_SUPPORTED; + */ + res = process_access_request(opts, &spadat); + } break; } diff --git a/server/pcap_capture.c b/server/pcap_capture.c index 671c40fe..59c3cafb 100644 --- a/server/pcap_capture.c +++ b/server/pcap_capture.c @@ -31,6 +31,7 @@ #include "incoming_spa.h" #include "config_init.h" #include "sig_handler.h" +#include "fw_util.h" #include "log_msg.h" /* The pcap capture routine. @@ -198,8 +199,7 @@ pcap_capture(fko_srv_options_t *opts) /* Check for any expired firewall rules and deal with them. */ - //--DSS TODO: still need to write this part... - //check_firewall_rules(opts); + check_firewall_rules(opts); usleep(10000); }