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
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
283
server/fw_util.c
283
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***/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user