Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/ipfw/ip_fw_eaction.c
Show First 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | destroy_eaction_obj(struct ip_fw_chain *ch, struct named_object *no) | ||||
ipfw_objhash_free_idx(ni, no->kidx); | ipfw_objhash_free_idx(ni, no->kidx); | ||||
free(obj, M_IPFW); | free(obj, M_IPFW); | ||||
} | } | ||||
/* | /* | ||||
* Resets all eaction opcodes to default handlers. | * Resets all eaction opcodes to default handlers. | ||||
*/ | */ | ||||
static void | static void | ||||
reset_eaction_obj(struct ip_fw_chain *ch, uint16_t eaction_id) | reset_eaction_rules(struct ip_fw_chain *ch, uint16_t eaction_id, | ||||
uint16_t instance_id, bool reset_rules) | |||||
{ | { | ||||
struct named_object *no; | struct named_object *no; | ||||
struct ip_fw *rule; | |||||
ipfw_insn *cmd; | |||||
int i; | int i; | ||||
IPFW_UH_WLOCK_ASSERT(ch); | IPFW_UH_WLOCK_ASSERT(ch); | ||||
no = ipfw_objhash_lookup_name_type(CHAIN_TO_SRV(ch), 0, | no = ipfw_objhash_lookup_name_type(CHAIN_TO_SRV(ch), 0, | ||||
IPFW_TLV_EACTION, default_eaction_typename); | IPFW_TLV_EACTION, default_eaction_typename); | ||||
if (no == NULL) | if (no == NULL) | ||||
panic("Default external action handler is not found"); | panic("Default external action handler is not found"); | ||||
if (eaction_id == no->kidx) | if (eaction_id == no->kidx) | ||||
panic("Wrong eaction_id"); | panic("Wrong eaction_id"); | ||||
EACTION_DEBUG("replace id %u with %u", eaction_id, no->kidx); | |||||
EACTION_DEBUG("Going to replace id %u with %u", eaction_id, no->kidx); | |||||
IPFW_WLOCK(ch); | IPFW_WLOCK(ch); | ||||
/* | |||||
* Reset eaction objects only if it is referenced by rules. | |||||
* But always reset objects for orphaned dynamic states. | |||||
*/ | |||||
if (reset_rules) { | |||||
for (i = 0; i < ch->n_rules; i++) { | for (i = 0; i < ch->n_rules; i++) { | ||||
rule = ch->map[i]; | |||||
cmd = ACTION_PTR(rule); | |||||
if (cmd->opcode != O_EXTERNAL_ACTION) | |||||
continue; | |||||
if (cmd->arg1 != eaction_id) | |||||
continue; | |||||
cmd->arg1 = no->kidx; /* Set to default id */ | |||||
/* | /* | ||||
* XXX: we only bump refcount on default_eaction. | |||||
* Refcount on the original object will be just | * Refcount on the original object will be just | ||||
* ignored on destroy. But on default_eaction it | * ignored on destroy. Refcount on default_eaction | ||||
* will be decremented on rule deletion. | * will be decremented on rule deletion, thus we | ||||
* need to reference default_eaction object. | |||||
*/ | */ | ||||
if (ipfw_reset_eaction(ch, ch->map[i], eaction_id, | |||||
no->kidx, instance_id) != 0) | |||||
no->refcnt++; | no->refcnt++; | ||||
/* | |||||
* Since named_object related to this instance will be | |||||
* also destroyed, truncate the chain of opcodes to | |||||
* remove the rest of cmd chain just after O_EXTERNAL_ACTION | |||||
* opcode. | |||||
*/ | |||||
if (rule->act_ofs < rule->cmd_len - 1) { | |||||
EACTION_DEBUG("truncate rule %d: len %u -> %u", | |||||
rule->rulenum, rule->cmd_len, rule->act_ofs + 1); | |||||
rule->cmd_len = rule->act_ofs + 1; | |||||
} | } | ||||
} | } | ||||
/* | |||||
* Reset eaction opcodes for orphaned dynamic states. | |||||
* Since parent rules are already deleted, we don't need to | |||||
* reference named object of default_eaction. | |||||
*/ | |||||
ipfw_dyn_reset_eaction(ch, eaction_id, no->kidx, instance_id); | |||||
IPFW_WUNLOCK(ch); | IPFW_WUNLOCK(ch); | ||||
} | } | ||||
/* | /* | ||||
* Initialize external actions framework. | * Initialize external actions framework. | ||||
* Create object with default eaction handler "drop". | * Create object with default eaction handler "drop". | ||||
*/ | */ | ||||
int | int | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | ipfw_del_eaction(struct ip_fw_chain *ch, uint16_t eaction_id) | ||||
struct named_object *no; | struct named_object *no; | ||||
IPFW_UH_WLOCK(ch); | IPFW_UH_WLOCK(ch); | ||||
no = ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), eaction_id); | no = ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), eaction_id); | ||||
if (no == NULL || no->etlv != IPFW_TLV_EACTION) { | if (no == NULL || no->etlv != IPFW_TLV_EACTION) { | ||||
IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (no->refcnt > 1) | reset_eaction_rules(ch, eaction_id, 0, (no->refcnt > 1)); | ||||
reset_eaction_obj(ch, eaction_id); | |||||
EACTION_DEBUG("External action '%s' with id %u unregistered", | EACTION_DEBUG("External action '%s' with id %u unregistered", | ||||
no->name, eaction_id); | no->name, eaction_id); | ||||
destroy_eaction_obj(ch, no); | destroy_eaction_obj(ch, no); | ||||
IPFW_UH_WUNLOCK(ch); | IPFW_UH_WUNLOCK(ch); | ||||
return (0); | |||||
} | |||||
int | |||||
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; | |||||
IPFW_UH_WLOCK_ASSERT(ch); | |||||
IPFW_WLOCK_ASSERT(ch); | |||||
cmd = ACTION_PTR(rule); | |||||
if (cmd->opcode != O_EXTERNAL_ACTION || | |||||
cmd->arg1 != eaction_id) | |||||
return (0); | |||||
if (instance_id != 0 && rule->act_ofs < rule->cmd_len - 1) { | |||||
icmd = cmd + 1; | |||||
if (icmd->opcode != O_EXTERNAL_INSTANCE || | |||||
icmd->arg1 != instance_id) | |||||
return (0); | |||||
/* FALLTHROUGH */ | |||||
} | |||||
cmd->arg1 = default_id; /* Set to default id */ | |||||
/* | |||||
* Since named_object related to this instance will be | |||||
* also destroyed, truncate the chain of opcodes to | |||||
* remove the rest of cmd chain just after O_EXTERNAL_ACTION | |||||
* opcode. | |||||
*/ | |||||
if (rule->act_ofs < rule->cmd_len - 1) { | |||||
EACTION_DEBUG("truncate rule %d: len %u -> %u", | |||||
rule->rulenum, rule->cmd_len, rule->act_ofs + 1); | |||||
rule->cmd_len = rule->act_ofs + 1; | |||||
} | |||||
/* | |||||
* Return 1 when reset successfully happened. | |||||
*/ | |||||
return (1); | |||||
} | |||||
/* | |||||
* This function should be called before external action instance is | |||||
* destroyed. It will reset eaction_id to default_id for rules, where | |||||
* eaction has instance with id == kidx. | |||||
*/ | |||||
int | |||||
ipfw_reset_eaction_instance(struct ip_fw_chain *ch, uint16_t eaction_id, | |||||
uint16_t kidx) | |||||
{ | |||||
struct named_object *no; | |||||
IPFW_UH_WLOCK_ASSERT(ch); | |||||
no = ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), eaction_id); | |||||
if (no == NULL || no->etlv != IPFW_TLV_EACTION) | |||||
return (EINVAL); | |||||
reset_eaction_rules(ch, eaction_id, kidx, 0); | |||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args, | ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args, | ||||
ipfw_insn *cmd, int *done) | ipfw_insn *cmd, int *done) | ||||
{ | { | ||||
return (EACTION_OBJ(ch, cmd)->handler(ch, args, cmd, done)); | return (EACTION_OBJ(ch, cmd)->handler(ch, args, cmd, done)); | ||||
} | } |