dd ipfw_get_action() function to get the pointer to action opcode.

ACTION_PTR() returns pointer to the start of rule action section,
but rule can keep several rule modifiers like O_LOG, O_TAG and O_ALTQ,
and only then real action opcode is stored.

ipfw_get_action() function inspects the rule action section, skips
all modifiers and returns action opcode.

Use this function in ipfw_reset_eaction() and flush_nat_ptrs().

MFC after:	1 week
Sponsored by:	Yandex LLC
This commit is contained in:
Andrey V. Elsukov 2019-07-29 15:09:12 +00:00
parent 52bb6100e9
commit e758846c09
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=350417
4 changed files with 44 additions and 17 deletions

View File

@ -377,33 +377,30 @@ ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule,
uint16_t eaction_id, uint16_t default_id, uint16_t instance_id)
{
ipfw_insn *cmd, *icmd;
int l, cmdlen;
int l;
IPFW_UH_WLOCK_ASSERT(ch);
IPFW_WLOCK_ASSERT(ch);
cmd = ACTION_PTR(rule);
l = rule->cmd_len - rule->act_ofs;
while (l > 0) {
cmdlen = F_LEN(cmd);
l -= cmdlen;
if (cmd->opcode == O_EXTERNAL_ACTION || l <= 0)
break;
cmd += cmdlen;
}
/*
* Return if there is not O_EXTERNAL_ACTION or its id is
* different.
*/
cmd = ipfw_get_action(rule);
if (cmd->opcode != O_EXTERNAL_ACTION ||
cmd->arg1 != eaction_id)
return (0);
/*
* If instance_id is specified, we need to truncate the
* rule length. Check if there is O_EXTERNAL_INSTANCE opcode.
*
* NOTE: F_LEN(cmd) must be 1 for O_EXTERNAL_ACTION opcode,
* and rule length should be enough to keep O_EXTERNAL_INSTANCE
* opcode, thus we do check for l > 1.
*/
if (instance_id != 0 && l > 0) {
MPASS(cmdlen == 1);
l = rule->cmd + rule->cmd_len - cmd;
if (instance_id != 0 && l > 1) {
MPASS(F_LEN(cmd) == 1);
icmd = cmd + 1;
if (icmd->opcode != O_EXTERNAL_INSTANCE ||
icmd->arg1 != instance_id)
@ -415,8 +412,9 @@ ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule,
* opcode.
*/
EACTION_DEBUG("truncate rule %d: len %u -> %u",
rule->rulenum, rule->cmd_len, rule->cmd_len - l);
rule->cmd_len -= l;
rule->rulenum, rule->cmd_len,
rule->cmd_len - F_LEN(icmd));
rule->cmd_len -= F_LEN(icmd);
MPASS(((uint32_t *)icmd -
(uint32_t *)rule->cmd) == rule->cmd_len);
}

View File

@ -140,13 +140,12 @@ ifaddr_change(void *arg __unused, struct ifnet *ifp)
static void
flush_nat_ptrs(struct ip_fw_chain *chain, const int ix)
{
int i;
ipfw_insn_nat *cmd;
int i;
IPFW_WLOCK_ASSERT(chain);
for (i = 0; i < chain->n_rules; i++) {
cmd = (ipfw_insn_nat *)ACTION_PTR(chain->map[i]);
/* XXX skip log and the like ? */
cmd = (ipfw_insn_nat *)ipfw_get_action(chain->map[i]);
if (cmd->o.opcode == O_NAT && cmd->nat != NULL &&
(ix < 0 || cmd->nat->id == ix))
cmd->nat = NULL;

View File

@ -665,6 +665,7 @@ struct ip_fw *ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize);
void ipfw_free_rule(struct ip_fw *rule);
int ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt);
int ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint16_t kidx);
ipfw_insn *ipfw_get_action(struct ip_fw *);
typedef int (sopt_handler_f)(struct ip_fw_chain *ch,
ip_fw3_opheader *op3, struct sockopt_data *sd);

View File

@ -1217,6 +1217,35 @@ move_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
return (0);
}
/*
* Returns pointer to action instruction, skips all possible rule
* modifiers like O_LOG, O_TAG, O_ALTQ.
*/
ipfw_insn *
ipfw_get_action(struct ip_fw *rule)
{
ipfw_insn *cmd;
int l, cmdlen;
cmd = ACTION_PTR(rule);
l = rule->cmd_len - rule->act_ofs;
while (l > 0) {
switch (cmd->opcode) {
case O_ALTQ:
case O_LOG:
case O_TAG:
break;
default:
return (cmd);
}
cmdlen = F_LEN(cmd);
l -= cmdlen;
cmd += cmdlen;
}
panic("%s: rule (%p) has not action opcode", __func__, rule);
return (NULL);
}
/*
* Clear counters for a specific rule.
* Normally run under IPFW_UH_RLOCK, but these are idempotent ops