kernel-netlink: Enable ICMP forwarding on inbound SA and out/fwd policies

This commit is contained in:
Tobias Brunner
2026-02-12 14:23:44 +01:00
parent 21e5edab10
commit 11351f24ef
@@ -554,6 +554,9 @@ struct policy_sa_t {
/** Whether to trigger per-CPU acquires for this policy */ /** Whether to trigger per-CPU acquires for this policy */
bool pcpu_acquires; bool pcpu_acquires;
/** Whether to forward certain ICMP error messages for this policy */
bool forward_icmp;
/** Assigned SA */ /** Assigned SA */
ipsec_sa_t *sa; ipsec_sa_t *sa;
}; };
@@ -577,19 +580,16 @@ struct policy_sa_out_t {
* Create a policy_sa(_out)_t object * Create a policy_sa(_out)_t object
*/ */
static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this, static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
policy_dir_t dir, policy_type_t type, host_t *src, host_t *dst, kernel_ipsec_policy_id_t *id, kernel_ipsec_manage_policy_t *data)
traffic_selector_t *src_ts, traffic_selector_t *dst_ts, mark_t mark,
uint32_t if_id, hw_offload_t hw_offload, bool pcpu_acquires,
ipsec_sa_cfg_t *cfg)
{ {
policy_sa_t *policy; policy_sa_t *policy;
if (dir == POLICY_OUT) if (id->dir == POLICY_OUT)
{ {
policy_sa_out_t *out; policy_sa_out_t *out;
INIT(out, INIT(out,
.src_ts = src_ts->clone(src_ts), .src_ts = id->src_ts->clone(id->src_ts),
.dst_ts = dst_ts->clone(dst_ts), .dst_ts = id->dst_ts->clone(id->dst_ts),
); );
policy = &out->generic; policy = &out->generic;
} }
@@ -597,9 +597,11 @@ static policy_sa_t *policy_sa_create(private_kernel_netlink_ipsec_t *this,
{ {
INIT(policy, .priority = 0); INIT(policy, .priority = 0);
} }
policy->type = type; policy->type = data->type;
policy->pcpu_acquires = pcpu_acquires; policy->pcpu_acquires = data->pcpu_acquires;
policy->sa = ipsec_sa_create(this, src, dst, mark, if_id, hw_offload, cfg); policy->forward_icmp = data->forward_icmp;
policy->sa = ipsec_sa_create(this, data->src, data->dst, id->mark,
id->if_id, data->hw_offload, data->sa);
return policy; return policy;
} }
@@ -1807,6 +1809,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
sa->flags |= XFRM_STATE_NOECN; sa->flags |= XFRM_STATE_NOECN;
} }
if (data->inbound && data->forward_icmp)
{
sa->flags |= XFRM_STATE_ICMP;
}
if (data->inbound) if (data->inbound)
{ {
switch (data->copy_dscp) switch (data->copy_dscp)
@@ -3065,6 +3072,12 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this,
: XFRM_POLICY_BLOCK; : XFRM_POLICY_BLOCK;
policy_info->share = XFRM_SHARE_ANY; policy_info->share = XFRM_SHARE_ANY;
if (mapping->type == POLICY_IPSEC && policy->direction != POLICY_IN &&
mapping->forward_icmp)
{
policy_info->flags |= XFRM_POLICY_ICMP;
}
/* policies don't expire */ /* policies don't expire */
policy_info->lft.soft_byte_limit = XFRM_INF; policy_info->lft.soft_byte_limit = XFRM_INF;
policy_info->lft.soft_packet_limit = XFRM_INF; policy_info->lft.soft_packet_limit = XFRM_INF;
@@ -3262,10 +3275,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
} }
/* cache the assigned IPsec SA */ /* cache the assigned IPsec SA */
assigned_sa = policy_sa_create(this, id->dir, data->type, data->src, assigned_sa = policy_sa_create(this, id, data);
data->dst, id->src_ts, id->dst_ts, id->mark,
id->if_id, data->hw_offload,
data->pcpu_acquires, data->sa);
assigned_sa->auto_priority = get_priority(policy, data->prio, id->interface); assigned_sa->auto_priority = get_priority(policy, data->prio, id->interface);
assigned_sa->priority = this->get_priority ? this->get_priority(id, data) assigned_sa->priority = this->get_priority ? this->get_priority(id, data)
: data->manual_prio; : data->manual_prio;
@@ -3499,6 +3509,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
auto_priority == mapping->auto_priority && auto_priority == mapping->auto_priority &&
data->type == mapping->type && data->type == mapping->type &&
data->pcpu_acquires == mapping->pcpu_acquires && data->pcpu_acquires == mapping->pcpu_acquires &&
data->forward_icmp == mapping->forward_icmp &&
ipsec_sa_equals(mapping->sa, &assigned_sa)) ipsec_sa_equals(mapping->sa, &assigned_sa))
{ {
current->used_by->remove_at(current->used_by, enumerator); current->used_by->remove_at(current->used_by, enumerator);