static unsigned int nat64_core(struct sk_buff *skb_in, bool (*compute_out_tuple_fn)(struct tuple *, struct sk_buff *, struct tuple *), bool (*translate_packet_fn)(struct tuple *, struct sk_buff *, struct sk_buff **), bool (*send_packet_fn)(struct sk_buff *, struct sk_buff *)) { struct sk_buff *skb_out = NULL; struct tuple tuple_in, tuple_out; if (!determine_in_tuple(skb_in, &tuple_in)) goto free_and_fail; if (filtering_and_updating(skb_in, &tuple_in) != NF_ACCEPT) goto free_and_fail; if (!compute_out_tuple_fn(&tuple_in, skb_in, &tuple_out)) goto free_and_fail; if (!translate_packet_fn(&tuple_out, skb_in, &skb_out)) goto free_and_fail; if (is_hairpin(&tuple_out)) { if (!handling_hairpinning(skb_out, &tuple_out)) goto free_and_fail; } else { if (!send_packet_fn(skb_in, skb_out)) goto fail; } log_debug("Success."); return NF_DROP; /* Lol, the irony. */ free_and_fail: kfree_skb(skb_out); /* Fall through. */ fail: log_debug("Failure."); return NF_DROP; }
static unsigned int core_common(struct packet *in) { struct packet out; struct tuple tuple_in; struct tuple tuple_out; verdict result; result = determine_in_tuple(in, &tuple_in); if (result != VERDICT_CONTINUE) goto end; result = filtering_and_updating(in, &tuple_in); if (result != VERDICT_CONTINUE) goto end; result = compute_out_tuple(&tuple_in, &tuple_out, in); if (result != VERDICT_CONTINUE) goto end; result = translating_the_packet(&tuple_out, in, &out); if (result != VERDICT_CONTINUE) goto end; if (is_hairpin(&out)) { result = handling_hairpinning(&out, &tuple_out); kfree_skb(out.skb); } else { result = sendpkt_send(in, &out); /* send_pkt releases skb_out regardless of verdict. */ } if (result != VERDICT_CONTINUE) goto end; log_debug("Success."); /* * The new packet was sent, so the original one can die; drop it. * * NF_DROP translates into an error (see nf_hook_slow()). * Sending a replacing & translated version of the packet should not count as an error, * so we free the incoming packet ourselves and return NF_STOLEN on success. */ kfree_skb(in->skb); result = VERDICT_STOLEN; /* Fall through. */ end: if (result == VERDICT_ACCEPT) log_debug("Returning the packet to the kernel."); return (unsigned int) result; }