From cd1624ff683694d9e635e44cc9ef851e3a60ef52 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 03:39:29 +0000 Subject: [PATCH 1/4] Tag netfilter hook ops with xlator_type; filter by type in xlator_find_netfilter Agent-Logs-Url: https://github.com/Dando-Real-ITA/Jool/sessions/43ba4fb6-57fe-4de3-b7e9-655d811f0e85 Co-authored-by: Dando-Real-ITA <3657228+Dando-Real-ITA@users.noreply.github.com> --- src/mod/common/kernel_hook_netfilter.c | 15 +++++++++++---- src/mod/common/xlator.c | 14 ++++++++++++-- src/mod/common/xlator.h | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/mod/common/kernel_hook_netfilter.c b/src/mod/common/kernel_hook_netfilter.c index b582fdfeb..f303f5167 100644 --- a/src/mod/common/kernel_hook_netfilter.c +++ b/src/mod/common/kernel_hook_netfilter.c @@ -5,11 +5,12 @@ /* #pragma GCC diagnostic error "-Wframe-larger-than=1" */ -static verdict find_instance(struct sk_buff *skb, struct xlator *result) +static verdict find_instance(struct sk_buff *skb, xlator_type xt, + struct xlator *result) { int error; - error = xlator_find_netfilter(dev_net(skb->dev), result); + error = xlator_find_netfilter(dev_net(skb->dev), xt, result); switch (error) { case 0: return VERDICT_CONTINUE; @@ -66,7 +67,10 @@ unsigned int hook_ipv6(void *priv, struct sk_buff *skb, if (!state) return NF_DROP; - result = find_instance(skb, &state->jool); + { + xlator_type xt = (xlator_type)(uintptr_t)priv; + result = find_instance(skb, xt, &state->jool); + } if (result != VERDICT_CONTINUE) goto end; enable_debug = state->jool.globals.debug; @@ -94,7 +98,10 @@ unsigned int hook_ipv4(void *priv, struct sk_buff *skb, if (!state) return NF_DROP; - result = find_instance(skb, &state->jool); + { + xlator_type xt = (xlator_type)(uintptr_t)priv; + result = find_instance(skb, xt, &state->jool); + } if (result != VERDICT_CONTINUE) goto end; enable_debug = state->jool.globals.debug; diff --git a/src/mod/common/xlator.c b/src/mod/common/xlator.c index e0012be8a..26deebdfa 100644 --- a/src/mod/common/xlator.c +++ b/src/mod/common/xlator.c @@ -442,6 +442,15 @@ static int __xlator_add(struct jool_instance *new, struct xlator *result) memcpy(ops, netfilter_hooks, sizeof(netfilter_hooks)); + /* Tag each hook op with the translator type so the hook callback + * can look up the correct instance (NAT64 vs SIIT). */ + { + int i; + xlator_type xt = xlator_flags2xt(new->jool.flags); + for (i = 0; i < ARRAY_SIZE(netfilter_hooks); i++) + ops[i].priv = (void *)(uintptr_t)xt; + } + error = nf_register_net_hooks(new->jool.ns, ops, ARRAY_SIZE(netfilter_hooks)); if (error) { @@ -832,7 +841,7 @@ int xlator_find_current(const char *iname, xlator_flags flags, return error; } -int xlator_find_netfilter(struct net *ns, struct xlator *result) +int xlator_find_netfilter(struct net *ns, xlator_type xt, struct xlator *result) { struct list_head *list; struct jool_instance *instance; @@ -841,7 +850,8 @@ int xlator_find_netfilter(struct net *ns, struct xlator *result) list = rcu_dereference_bh(netfilter_instances); list_for_each_entry_rcu(instance, list, list_hook) { - if (ns == instance->jool.ns) { + if (ns == instance->jool.ns + && xlator_flags2xt(instance->jool.flags) == xt) { xlator_get(&instance->jool); memcpy(result, &instance->jool, sizeof(*result)); rcu_read_unlock_bh(); diff --git a/src/mod/common/xlator.h b/src/mod/common/xlator.h index 37f451cc8..e561dff12 100644 --- a/src/mod/common/xlator.h +++ b/src/mod/common/xlator.h @@ -72,7 +72,7 @@ int xlator_find(struct net *ns, xlator_flags flags, const char *iname, struct xlator *result); int xlator_find_current(const char *iname, xlator_flags flags, struct xlator *result); -int xlator_find_netfilter(struct net *ns, struct xlator *result); +int xlator_find_netfilter(struct net *ns, xlator_type xt, struct xlator *result); void xlator_put(struct xlator *instance); typedef int (*xlator_foreach_cb)(struct xlator *, void *); From 9dd6019fe1c5778edba6eb51711e7e0bc67d208c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 23:55:39 +0000 Subject: [PATCH 2/4] feat: add hook-level debug logs and ensure NAT64 runs before SIIT Agent-Logs-Url: https://github.com/Dando-Real-ITA/Jool/sessions/e67bf607-3126-4dc8-88fa-0e0386e06216 Co-authored-by: Dando-Real-ITA <3657228+Dando-Real-ITA@users.noreply.github.com> --- src/mod/common/kernel_hook_iptables.c | 19 +++++++++++++++++++ src/mod/common/kernel_hook_netfilter.c | 19 +++++++++++++++++++ src/mod/common/xlator.c | 19 +++++++++++++++++-- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/mod/common/kernel_hook_iptables.c b/src/mod/common/kernel_hook_iptables.c index ba9d82d89..0bd4815a6 100644 --- a/src/mod/common/kernel_hook_iptables.c +++ b/src/mod/common/kernel_hook_iptables.c @@ -2,6 +2,8 @@ #include "mod/common/kernel_hook.h" +#include +#include #include "common/iptables.h" #include "mod/common/core.h" #include "mod/common/log.h" @@ -70,6 +72,7 @@ static unsigned int verdict2iptables(verdict result, bool enable_debug) { switch (result) { case VERDICT_STOLEN: + ____log_debug(enable_debug, "Packet stolen (translated successfully)."); return NF_STOLEN; /* This is the happy path. */ case VERDICT_UNTRANSLATABLE: ____log_debug(enable_debug, "Returning packet to the iptables chain."); @@ -108,6 +111,14 @@ unsigned int target_ipv6(struct sk_buff *skb, goto end; enable_debug = state->jool.globals.debug; + ____log_debug(enable_debug, + "target_ipv6 %s/%s: src=%pI6c dst=%pI6c dev=%s", + xt2str(xlator_get_type(&state->jool)), + state->jool.iname, + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->dev ? skb->dev->name : "(none)"); + result = core_6to4(skb, state); xlator_put(&state->jool); @@ -137,6 +148,14 @@ unsigned int target_ipv4(struct sk_buff *skb, goto end; enable_debug = state->jool.globals.debug; + ____log_debug(enable_debug, + "target_ipv4 %s/%s: src=%pI4 dst=%pI4 dev=%s", + xt2str(xlator_get_type(&state->jool)), + state->jool.iname, + &ip_hdr(skb)->saddr, + &ip_hdr(skb)->daddr, + skb->dev ? skb->dev->name : "(none)"); + result = core_4to6(skb, state); xlator_put(&state->jool); diff --git a/src/mod/common/kernel_hook_netfilter.c b/src/mod/common/kernel_hook_netfilter.c index f303f5167..131f45d1b 100644 --- a/src/mod/common/kernel_hook_netfilter.c +++ b/src/mod/common/kernel_hook_netfilter.c @@ -1,5 +1,7 @@ #include "mod/common/kernel_hook.h" +#include +#include #include "mod/common/log.h" #include "mod/common/core.h" @@ -35,6 +37,7 @@ static unsigned int verdict2netfilter(verdict result, bool enable_debug) { switch (result) { case VERDICT_STOLEN: + ____log_debug(enable_debug, "Packet stolen (translated successfully)."); return NF_STOLEN; /* This is the happy path. */ case VERDICT_UNTRANSLATABLE: ____log_debug(enable_debug, "Returning the packet to the kernel."); @@ -75,6 +78,14 @@ unsigned int hook_ipv6(void *priv, struct sk_buff *skb, goto end; enable_debug = state->jool.globals.debug; + ____log_debug(enable_debug, + "hook_ipv6 %s/%s: src=%pI6c dst=%pI6c dev=%s", + xt2str(xlator_get_type(&state->jool)), + state->jool.iname, + &ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->dev ? skb->dev->name : "(none)"); + result = core_6to4(skb, state); xlator_put(&state->jool); @@ -106,6 +117,14 @@ unsigned int hook_ipv4(void *priv, struct sk_buff *skb, goto end; enable_debug = state->jool.globals.debug; + ____log_debug(enable_debug, + "hook_ipv4 %s/%s: src=%pI4 dst=%pI4 dev=%s", + xt2str(xlator_get_type(&state->jool)), + state->jool.iname, + &ip_hdr(skb)->saddr, + &ip_hdr(skb)->daddr, + skb->dev ? skb->dev->name : "(none)"); + result = core_4to6(skb, state); xlator_put(&state->jool); diff --git a/src/mod/common/xlator.c b/src/mod/common/xlator.c index 26deebdfa..0c77a7ec0 100644 --- a/src/mod/common/xlator.c +++ b/src/mod/common/xlator.c @@ -35,6 +35,14 @@ static struct nf_hook_ops netfilter_hooks[] = { }, }; +/* + * Priority offset added to SIIT instances so they always run after NAT64 + * within the same PRE_ROUTING hook chain. A value of 1 is sufficient since + * both translators share the same hook point and a higher priority number + * means the hook runs later. + */ +#define SIIT_PRIORITY_OFFSET 1 + /** * An xlator, except it's the database node version. */ @@ -443,12 +451,19 @@ static int __xlator_add(struct jool_instance *new, struct xlator *result) memcpy(ops, netfilter_hooks, sizeof(netfilter_hooks)); /* Tag each hook op with the translator type so the hook callback - * can look up the correct instance (NAT64 vs SIIT). */ + * can look up the correct instance (NAT64 vs SIIT). Adjust + * priority so NAT64 (unchanged) always runs before SIIT + * (+1 offset) within the same PRE_ROUTING hook chain. */ { int i; xlator_type xt = xlator_flags2xt(new->jool.flags); - for (i = 0; i < ARRAY_SIZE(netfilter_hooks); i++) + int prio_delta = (xt & XT_NAT64) ? 0 : SIIT_PRIORITY_OFFSET; + + for (i = 0; i < ARRAY_SIZE(netfilter_hooks); i++) { ops[i].priv = (void *)(uintptr_t)xt; + ops[i].priority = netfilter_hooks[i].priority + + prio_delta; + } } error = nf_register_net_hooks(new->jool.ns, ops, From fb1f1821eed4730aea4e11c7168bfd20448d33a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 12:33:34 +0000 Subject: [PATCH 3/4] fix: verdict logs now include instance context; ICMP inner-packet UNTRANSLATABLE no longer dropped Agent-Logs-Url: https://github.com/Dando-Real-ITA/Jool/sessions/03aef55a-c14b-4186-8534-e81730770eaa Co-authored-by: Dando-Real-ITA <3657228+Dando-Real-ITA@users.noreply.github.com> --- src/mod/common/kernel_hook_iptables.c | 57 ++++++++++++++------------ src/mod/common/kernel_hook_netfilter.c | 57 ++++++++++++++------------ src/mod/common/rfc7915/common.c | 15 ++++--- 3 files changed, 72 insertions(+), 57 deletions(-) diff --git a/src/mod/common/kernel_hook_iptables.c b/src/mod/common/kernel_hook_iptables.c index 0bd4815a6..f27a8f7c8 100644 --- a/src/mod/common/kernel_hook_iptables.c +++ b/src/mod/common/kernel_hook_iptables.c @@ -68,17 +68,22 @@ static struct net *action_param_net(const struct xt_action_param *param) return param->state->net; } -static unsigned int verdict2iptables(verdict result, bool enable_debug) +/* + * @jool: The active instance, or NULL when no instance was found. When NULL + * no debug logging is emitted (there is no debug flag to consult and no + * instance context to print). + */ +static unsigned int verdict2iptables(verdict result, struct xlator *jool) { switch (result) { case VERDICT_STOLEN: - ____log_debug(enable_debug, "Packet stolen (translated successfully)."); + __log_debug(jool, "Packet stolen (translated successfully)."); return NF_STOLEN; /* This is the happy path. */ case VERDICT_UNTRANSLATABLE: - ____log_debug(enable_debug, "Returning packet to the iptables chain."); + __log_debug(jool, "Returning packet to the iptables chain."); return XT_CONTINUE; case VERDICT_DROP: - ____log_debug(enable_debug, "Jool: Dropping packet."); + __log_debug(jool, "Dropping packet."); return NF_DROP; case VERDICT_CONTINUE: WARN(true, "At time of writing, Jool core is not supposed to return CONTINUE after the packet is handled.\n" @@ -99,7 +104,7 @@ unsigned int target_ipv6(struct sk_buff *skb, { struct xlation *state; verdict result; - bool enable_debug = false; + unsigned int xt_result; state = xlation_create(NULL); if (!state) @@ -107,23 +112,23 @@ unsigned int target_ipv6(struct sk_buff *skb, result = find_instance(action_param_net(param), param->targinfo, &state->jool); - if (result != VERDICT_CONTINUE) - goto end; - enable_debug = state->jool.globals.debug; - - ____log_debug(enable_debug, - "target_ipv6 %s/%s: src=%pI6c dst=%pI6c dev=%s", - xt2str(xlator_get_type(&state->jool)), - state->jool.iname, + if (result != VERDICT_CONTINUE) { + xlation_destroy(state); + return verdict2iptables(result, NULL); + } + + log_debug(state, + "target_ipv6: src=%pI6c dst=%pI6c dev=%s", &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev ? skb->dev->name : "(none)"); result = core_6to4(skb, state); + xt_result = verdict2iptables(result, &state->jool); xlator_put(&state->jool); -end: xlation_destroy(state); - return verdict2iptables(result, enable_debug); + xlation_destroy(state); + return xt_result; } EXPORT_SYMBOL_GPL(target_ipv6); @@ -136,7 +141,7 @@ unsigned int target_ipv4(struct sk_buff *skb, { struct xlation *state; verdict result; - bool enable_debug = false; + unsigned int xt_result; state = xlation_create(NULL); if (!state) @@ -144,23 +149,23 @@ unsigned int target_ipv4(struct sk_buff *skb, result = find_instance(action_param_net(param), param->targinfo, &state->jool); - if (result != VERDICT_CONTINUE) - goto end; - enable_debug = state->jool.globals.debug; - - ____log_debug(enable_debug, - "target_ipv4 %s/%s: src=%pI4 dst=%pI4 dev=%s", - xt2str(xlator_get_type(&state->jool)), - state->jool.iname, + if (result != VERDICT_CONTINUE) { + xlation_destroy(state); + return verdict2iptables(result, NULL); + } + + log_debug(state, + "target_ipv4: src=%pI4 dst=%pI4 dev=%s", &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, skb->dev ? skb->dev->name : "(none)"); result = core_4to6(skb, state); + xt_result = verdict2iptables(result, &state->jool); xlator_put(&state->jool); -end: xlation_destroy(state); - return verdict2iptables(result, enable_debug); + xlation_destroy(state); + return xt_result; } EXPORT_SYMBOL_GPL(target_ipv4); diff --git a/src/mod/common/kernel_hook_netfilter.c b/src/mod/common/kernel_hook_netfilter.c index 131f45d1b..386075410 100644 --- a/src/mod/common/kernel_hook_netfilter.c +++ b/src/mod/common/kernel_hook_netfilter.c @@ -33,17 +33,22 @@ static verdict find_instance(struct sk_buff *skb, xlator_type xt, return VERDICT_UNTRANSLATABLE; } -static unsigned int verdict2netfilter(verdict result, bool enable_debug) +/* + * @jool: The active instance, or NULL when no instance was found. When NULL + * no debug logging is emitted (there is no debug flag to consult and no + * instance context to print). + */ +static unsigned int verdict2netfilter(verdict result, struct xlator *jool) { switch (result) { case VERDICT_STOLEN: - ____log_debug(enable_debug, "Packet stolen (translated successfully)."); + __log_debug(jool, "Packet stolen (translated successfully)."); return NF_STOLEN; /* This is the happy path. */ case VERDICT_UNTRANSLATABLE: - ____log_debug(enable_debug, "Returning the packet to the kernel."); + __log_debug(jool, "Returning the packet to the kernel."); return NF_ACCEPT; case VERDICT_DROP: - ____log_debug(enable_debug, "Dropping packet."); + __log_debug(jool, "Dropping packet."); return NF_DROP; case VERDICT_CONTINUE: WARN(true, "At time of writing, Jool core is not supposed to return CONTINUE after the packet is handled.\n" @@ -64,7 +69,7 @@ unsigned int hook_ipv6(void *priv, struct sk_buff *skb, { struct xlation *state; verdict result; - bool enable_debug = false; + unsigned int nf_result; state = xlation_create(NULL); if (!state) @@ -74,23 +79,23 @@ unsigned int hook_ipv6(void *priv, struct sk_buff *skb, xlator_type xt = (xlator_type)(uintptr_t)priv; result = find_instance(skb, xt, &state->jool); } - if (result != VERDICT_CONTINUE) - goto end; - enable_debug = state->jool.globals.debug; - - ____log_debug(enable_debug, - "hook_ipv6 %s/%s: src=%pI6c dst=%pI6c dev=%s", - xt2str(xlator_get_type(&state->jool)), - state->jool.iname, + if (result != VERDICT_CONTINUE) { + xlation_destroy(state); + return verdict2netfilter(result, NULL); + } + + log_debug(state, + "hook_ipv6: src=%pI6c dst=%pI6c dev=%s", &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev ? skb->dev->name : "(none)"); result = core_6to4(skb, state); + nf_result = verdict2netfilter(result, &state->jool); xlator_put(&state->jool); -end: xlation_destroy(state); - return verdict2netfilter(result, enable_debug); + xlation_destroy(state); + return nf_result; } EXPORT_SYMBOL_GPL(hook_ipv6); @@ -103,7 +108,7 @@ unsigned int hook_ipv4(void *priv, struct sk_buff *skb, { struct xlation *state; verdict result; - bool enable_debug = false; + unsigned int nf_result; state = xlation_create(NULL); if (!state) @@ -113,22 +118,22 @@ unsigned int hook_ipv4(void *priv, struct sk_buff *skb, xlator_type xt = (xlator_type)(uintptr_t)priv; result = find_instance(skb, xt, &state->jool); } - if (result != VERDICT_CONTINUE) - goto end; - enable_debug = state->jool.globals.debug; - - ____log_debug(enable_debug, - "hook_ipv4 %s/%s: src=%pI4 dst=%pI4 dev=%s", - xt2str(xlator_get_type(&state->jool)), - state->jool.iname, + if (result != VERDICT_CONTINUE) { + xlation_destroy(state); + return verdict2netfilter(result, NULL); + } + + log_debug(state, + "hook_ipv4: src=%pI4 dst=%pI4 dev=%s", &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, skb->dev ? skb->dev->name : "(none)"); result = core_4to6(skb, state); + nf_result = verdict2netfilter(result, &state->jool); xlator_put(&state->jool); -end: xlation_destroy(state); - return verdict2netfilter(result, enable_debug); + xlation_destroy(state); + return nf_result; } EXPORT_SYMBOL_GPL(hook_ipv4); diff --git a/src/mod/common/rfc7915/common.c b/src/mod/common/rfc7915/common.c index c32fca323..232b9fe3f 100644 --- a/src/mod/common/rfc7915/common.c +++ b/src/mod/common/rfc7915/common.c @@ -195,18 +195,23 @@ verdict ttpcomm_translate_inner_packet(struct xlation *state, result = steps->xlat_inner_l3(state); if (result == VERDICT_UNTRANSLATABLE) { /* - * Accepting because of an inner packet doesn't make sense. - * Also we couldn't have translated this inner packet. + * This instance cannot translate the inner packet's L3 header + * (e.g. the address does not belong to this translator's pool). + * Return UNTRANSLATABLE so the packet is passed to the kernel + * (NF_ACCEPT) and another Jool instance in the hook chain (e.g. + * a SIIT instance co-existing with this NAT64) gets a chance to + * handle the ICMP error. */ - result = VERDICT_DROP; goto end; } if (result != VERDICT_CONTINUE) goto end; result = xlat_l4_function(state, steps); - if (result == VERDICT_UNTRANSLATABLE) - result = VERDICT_DROP; + /* + * If VERDICT_UNTRANSLATABLE, propagate it unchanged (same rationale as + * the xlat_inner_l3 case above: let the next Jool instance try). + */ end: restore_outer_packet(state, &bkp, true); From e8cfa495b497b49ef332a94ea2ec5dc88035fcf0 Mon Sep 17 00:00:00 2001 From: Gaspare Iengo Date: Mon, 27 Apr 2026 11:29:48 +0000 Subject: [PATCH 4/4] Ignore vscode --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 242ed661a..da5f711d2 100755 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ Thumbs.db .settings .metadata Debug/ +.vscode/ # autoconf ##########