[server] add NAT rule existence detection for --no-ipt-check support (issue #162)

This commit is contained in:
Michael Rash
2015-07-07 08:28:16 -04:00
parent 4874dc9c83
commit 5460509f88
4 changed files with 122 additions and 61 deletions

View File

@@ -59,29 +59,29 @@ zero_cmd_buffers(void)
static int pid_status = 0;
static void
chop_newline(char *str)
{
if(str[0] != 0x0 && str[strlen(str)-1] == 0x0a)
str[strlen(str)-1] = 0x0;
return;
}
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 srcip, const char * const dstip,
const unsigned int port, const unsigned int exp_ts)
const struct fw_chain * const fwc,
const unsigned int proto,
const char * const srcip,
const char * const dstip,
const unsigned int port,
const char * const natip,
const unsigned int nat_port,
const unsigned int exp_ts)
{
int rule_exists=0;
char cmd_buf[CMD_BUFSIZE] = {0};
char ipt_line_buf[CMD_BUFSIZE] = {0};
char target_search[CMD_BUFSIZE] = {0};
char proto_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};
char cmd_buf[CMD_BUFSIZE] = {0};
char ipt_line_buf[CMD_BUFSIZE] = {0};
char target_search[CMD_BUFSIZE] = {0};
char proto_search[CMD_BUFSIZE] = {0};
char srcip_search[CMD_BUFSIZE] = {0};
char dstip_search[CMD_BUFSIZE] = {0};
char natip_search[CMD_BUFSIZE] = {0};
char port_search[CMD_BUFSIZE] = {0};
char nat_port_search[CMD_BUFSIZE] = {0};
char exp_ts_search[CMD_BUFSIZE] = {0};
char *ndx = NULL;
#if CODE_COVERAGE
int pid_status = 0;
@@ -110,31 +110,69 @@ rule_exists_no_chk_support(const fko_srv_options_t * const opts,
snprintf(proto_search, CMD_BUFSIZE-1, " %u ", proto);
snprintf(port_search, CMD_BUFSIZE-1, "dpt:%u ", port);
snprintf(nat_port_search, CMD_BUFSIZE-1, ":%u", nat_port);
snprintf(target_search, CMD_BUFSIZE-1, " %s ", fwc->target);
snprintf(srcip_search, CMD_BUFSIZE-1, " %s ", srcip);
if (srcip != NULL)
snprintf(srcip_search, CMD_BUFSIZE-1, " %s ", srcip);
if (dstip != NULL)
{
snprintf(dstip_search, CMD_BUFSIZE-1, " %s ", dstip);
}
if (natip != NULL)
snprintf(dstip_search, CMD_BUFSIZE-1, " to:%s", natip);
snprintf(exp_ts_search, CMD_BUFSIZE-1, "%u ", exp_ts);
/* search for each of the substrings - the rule expiration time is the
* primary search method
*/
if(search_extcmd_getline(cmd_buf, ipt_line_buf,
CMD_BUFSIZE, NO_TIMEOUT, exp_ts_search, &pid_status, opts)
/* we have an iptables policy rule that matches the
* expiration time, so make sure this rule matches the
* other fields too. If not, then it is for different
* access requested by a separate SPA packet.
*/
&& ((proto == ANY_PROTO) ? 1 : (strstr(ipt_line_buf, proto_search) != NULL))
&& (strstr(ipt_line_buf, srcip_search) != NULL)
CMD_BUFSIZE, NO_TIMEOUT, exp_ts_search, &pid_status, opts))
{
chop_newline(ipt_line_buf);
/* we have an iptables policy rule that matches the
* expiration time, so make sure this rule matches the
* other fields too. If not, then it is for different
* access requested by a separate SPA packet.
*/
if(((proto == ANY_PROTO) ? 1 : (strstr(ipt_line_buf, proto_search) != NULL))
&& ((srcip == NULL) ? 1 : (strstr(ipt_line_buf, srcip_search) != NULL))
&& ((dstip == NULL) ? 1 : (strstr(ipt_line_buf, dstip_search) != NULL))
&& ((natip == NULL) ? 1 : (strstr(ipt_line_buf, natip_search) != NULL))
&& (strstr(ipt_line_buf, target_search) != NULL)
&& ((port == ANY_PORT) ? 1 : (strstr(ipt_line_buf, port_search) != NULL)))
{
rule_exists = 1;
}
}
/* If there is a nat port, we have to qualify it as part
* of the 'to:<ip>:<port>' portion of the rule (at the end)
*/
if(rule_exists && nat_port != NAT_ANY_PORT)
{
rule_exists = 1;
ndx = strstr(ipt_line_buf, " to:");
/* Make sure there isn't a duplicate " to:" string (i.e. if someone
* was trying to be tricky with the iptables comment match).
*/
if(ndx != NULL && (strstr((ndx+strlen(" to:")), " to:") == NULL))
{
ndx = strstr((ndx+strlen(" to:")), nat_port_search);
if (ndx == NULL)
{
rule_exists = 0;
}
else if((*(ndx+strlen(nat_port_search)) != '\0')
&& (*(ndx+strlen(nat_port_search)) != ' '))
{
rule_exists = 0;
}
}
else
{
rule_exists = 0;
}
}
if(rule_exists)
@@ -185,9 +223,14 @@ 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 srcip,
const char * const dstip, const unsigned int port,
const struct fw_chain * const fwc,
const char * const rule,
const unsigned int proto,
const char * const srcip,
const char * const dstip,
const unsigned int port,
const char * const nat_ip,
const unsigned int nat_port,
const unsigned int exp_ts)
{
int rule_exists = 0;
@@ -196,7 +239,8 @@ rule_exists(const fko_srv_options_t * const opts,
rule_exists = rule_exists_chk_support(opts, fwc->to_chain, rule);
else
rule_exists = rule_exists_no_chk_support(opts, fwc, proto, srcip,
(opts->fw_config->use_destination ? dstip : NULL), port, exp_ts);
(opts->fw_config->use_destination ? dstip : NULL), port,
nat_ip, nat_port, exp_ts);
if(rule_exists == 1)
log_msg(LOG_DEBUG, "rule_exists() Rule : '%s' in %s already exists",
@@ -435,7 +479,8 @@ jump_rule_exists_chk_support(const fko_srv_options_t * const opts, const int cha
}
static int
jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts, const int chain_num)
jump_rule_exists_no_chk_support(const fko_srv_options_t * const opts,
const int chain_num)
{
int exists = 0;
char cmd_buf[CMD_BUFSIZE] = {0};
@@ -962,11 +1007,17 @@ static void
ipt_rule(const fko_srv_options_t * const opts,
const char * const complete_rule_buf,
const char * const fw_rule_macro,
const char * const srcip, const char * const dstip,
const unsigned int proto, const unsigned int port,
const char * const srcip,
const char * const dstip,
const unsigned int proto,
const unsigned int port,
const char * const nat_ip,
const unsigned int nat_port,
struct fw_chain * const chain,
const unsigned int exp_ts, const time_t now,
const char * const msg, const char * const access_msg)
const unsigned int exp_ts,
const time_t now,
const char * const msg,
const char * const access_msg)
{
char rule_buf[CMD_BUFSIZE] = {0};
@@ -989,12 +1040,12 @@ ipt_rule(const fko_srv_options_t * const opts,
);
}
/* Check to make sure that the chain and jump rule exists
/* Check to make sure that the chain and jump rule exist
*/
mk_chain(opts, chain->type);
if(rule_exists(opts, chain, rule_buf,
proto, srcip, dstip, port, exp_ts) == 0)
if(rule_exists(opts, chain, rule_buf, proto, srcip,
dstip, port, nat_ip, nat_port, exp_ts) == 0)
{
if(create_rule(opts, chain->to_chain, rule_buf))
{
@@ -1047,17 +1098,16 @@ static void forward_access_rule(const fko_srv_options_t * const opts,
/* Make a global ACCEPT rule for all ports/protocols
*/
ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip,
NULL, ANY_PROTO, ANY_PORT, fwd_chain, exp_ts, now,
"FORWARD ALL", "*/*");
NULL, ANY_PROTO, ANY_PORT, NULL, NAT_ANY_PORT,
fwd_chain, exp_ts, now, "FORWARD ALL", "*/*");
}
else
{
/* Make the FORWARD access rule
*/
ipt_rule(opts, NULL, IPT_FWD_RULE_ARGS, spadat->use_src_ip,
nat_ip, fst_proto, nat_port, fwd_chain, exp_ts, now,
"FORWARD", spadat->spa_message_remain);
nat_ip, fst_proto, nat_port, NULL, NAT_ANY_PORT,
fwd_chain, exp_ts, now, "FORWARD", spadat->spa_message_remain);
}
return;
}
@@ -1094,8 +1144,8 @@ static void dnat_rule(const fko_srv_options_t * const opts,
/* Make a global DNAT rule for all ports/protocols
*/
ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip,
NULL, ANY_PROTO, ANY_PORT, dnat_chain, exp_ts, now,
"DNAT ALL", "*/*");
NULL, ANY_PROTO, ANY_PORT, NULL, NAT_ANY_PORT,
dnat_chain, exp_ts, now, "DNAT ALL", "*/*");
}
else
{
@@ -1115,8 +1165,8 @@ static void dnat_rule(const fko_srv_options_t * const opts,
ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip,
(fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP),
fst_proto, fst_port, dnat_chain, exp_ts, now, "DNAT",
spadat->spa_message_remain);
fst_proto, fst_port, nat_ip, nat_port, dnat_chain, exp_ts, now,
"DNAT", spadat->spa_message_remain);
}
return;
}
@@ -1176,8 +1226,8 @@ static void snat_rule(const fko_srv_options_t * const opts,
);
ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip,
NULL, ANY_PROTO, ANY_PORT, snat_chain, exp_ts, now,
"SNAT ALL", "*/*");
NULL, ANY_PROTO, ANY_PORT, NULL, NAT_ANY_PORT,
snat_chain, exp_ts, now, "SNAT ALL", "*/*");
}
else
{
@@ -1227,7 +1277,8 @@ static void snat_rule(const fko_srv_options_t * const opts,
);
ipt_rule(opts, rule_buf, NULL, spadat->use_src_ip,
NULL, fst_proto, nat_port, snat_chain, exp_ts, now, "SNAT",
NULL, fst_proto, nat_port, nat_ip, nat_port,
snat_chain, exp_ts, now, "SNAT",
spadat->spa_message_remain);
}
return;
@@ -1328,8 +1379,8 @@ process_spa_request(const fko_srv_options_t * const opts,
{
ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip,
(fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP),
fst_proto, nat_port, in_chain, exp_ts, now, "local NAT",
spadat->spa_message_remain);
fst_proto, nat_port, nat_ip, nat_port, in_chain, exp_ts,
now, "local NAT", spadat->spa_message_remain);
}
else if(strlen(fwd_chain->to_chain))
{
@@ -1359,8 +1410,8 @@ process_spa_request(const fko_srv_options_t * const opts,
{
ipt_rule(opts, NULL, IPT_RULE_ARGS, spadat->use_src_ip,
(fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP),
ple->proto, ple->port, in_chain, exp_ts, now, "access",
spadat->spa_message_remain);
ple->proto, ple->port, NULL, NAT_ANY_PORT,
in_chain, exp_ts, now, "access", spadat->spa_message_remain);
/* We need to make a corresponding OUTPUT rule if out_chain target
* is not NULL.
@@ -1369,8 +1420,8 @@ process_spa_request(const fko_srv_options_t * const opts,
{
ipt_rule(opts, NULL, IPT_OUT_RULE_ARGS, spadat->use_src_ip,
(fwc.use_destination ? spadat->pkt_destination_ip : IPT_ANY_IP),
ple->proto, ple->port, out_chain, exp_ts, now, "OUTPUT",
spadat->spa_message_remain);
ple->proto, ple->port, NULL, NAT_ANY_PORT,
out_chain, exp_ts, now, "OUTPUT", spadat->spa_message_remain);
}
ple = ple->next;
}

View File

@@ -64,6 +64,7 @@
#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"
#define IPT_NAT_ANY_IP IPT_ANY_IP
int validate_ipt_chain_conf(const char * const chain_str);

View File

@@ -186,6 +186,14 @@ verify_file_perms_ownership(const char *file)
return 1;
}
void
chop_newline(char *str)
{
if(str != NULL && str[0] != 0x0 && str[strlen(str)-1] == 0x0a)
str[strlen(str)-1] = 0x0;
return;
}
static int
add_argv(char **argv_new, int *argc_new,
const char *new_arg, const fko_srv_options_t * const opts)

View File

@@ -64,6 +64,7 @@ char* dump_ctx(fko_ctx_t ctx);
int is_valid_dir(const char *path);
int is_valid_exe(const char *path);
int verify_file_perms_ownership(const char *file);
void chop_newline(char *str);
int strtoargv(const char * const args_str, char **argv_new, int *argc_new,
const fko_srv_options_t * const opts);
void free_argv(char **argv_new, int *argc_new);