Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Thumbs.db
.settings
.metadata
Debug/
.vscode/

# autoconf
##########
Expand Down
54 changes: 39 additions & 15 deletions src/mod/common/kernel_hook_iptables.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "mod/common/kernel_hook.h"

#include <linux/ip.h>
#include <linux/ipv6.h>
#include "common/iptables.h"
#include "mod/common/core.h"
#include "mod/common/log.h"
Expand Down Expand Up @@ -66,16 +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(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"
Expand All @@ -96,23 +104,31 @@ 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)
return NF_DROP;

result = find_instance(action_param_net(param), param->targinfo,
&state->jool);
if (result != VERDICT_CONTINUE)
goto end;
enable_debug = state->jool.globals.debug;
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);

Expand All @@ -125,23 +141,31 @@ 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)
return NF_DROP;

result = find_instance(action_param_net(param), param->targinfo,
&state->jool);
if (result != VERDICT_CONTINUE)
goto end;
enable_debug = state->jool.globals.debug;
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);

Expand Down
69 changes: 50 additions & 19 deletions src/mod/common/kernel_hook_netfilter.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#include "mod/common/kernel_hook.h"

#include <linux/ip.h>
#include <linux/ipv6.h>
#include "mod/common/log.h"
#include "mod/common/core.h"

/* #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;
Expand All @@ -30,16 +33,22 @@ static verdict find_instance(struct sk_buff *skb, struct xlator *result)
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(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"
Expand All @@ -60,22 +69,33 @@ 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)
return NF_DROP;

result = find_instance(skb, &state->jool);
if (result != VERDICT_CONTINUE)
goto end;
enable_debug = state->jool.globals.debug;
{
xlator_type xt = (xlator_type)(uintptr_t)priv;
result = find_instance(skb, xt, &state->jool);
}
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);

Expand All @@ -88,21 +108,32 @@ 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)
return NF_DROP;

result = find_instance(skb, &state->jool);
if (result != VERDICT_CONTINUE)
goto end;
enable_debug = state->jool.globals.debug;
{
xlator_type xt = (xlator_type)(uintptr_t)priv;
result = find_instance(skb, xt, &state->jool);
}
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);
15 changes: 10 additions & 5 deletions src/mod/common/rfc7915/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
29 changes: 27 additions & 2 deletions src/mod/common/xlator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -442,6 +450,22 @@ 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). 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);
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,
ARRAY_SIZE(netfilter_hooks));
if (error) {
Expand Down Expand Up @@ -832,7 +856,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;
Expand All @@ -841,7 +865,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();
Expand Down
2 changes: 1 addition & 1 deletion src/mod/common/xlator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *);
Expand Down