Exemple #1
0
/**
 * Mirrors the core's behavior by processing skb_in as if it was the incoming packet.
 *
 * @param skb_in the outgoing packet. Except because it's a hairpin, here it's treated as if it was
 *		the one received from the network.
 * @param tuple_in skb_in's tuple.
 * @return whether we managed to U-turn the packet successfully.
 */
verdict handling_hairpinning(struct sk_buff *skb_in, struct tuple *tuple_in)
{
	struct sk_buff *skb_out;
	struct tuple tuple_out;
	verdict result;

	log_debug("Step 5: Handling Hairpinning...");

	if (skb_l4_proto(skb_in) == L4PROTO_ICMP) {
		/* RFC 6146 section 2 (Definition of "Hairpinning"). */
		log_debug("ICMP is not supported by hairpinning. Dropping packet...");
		return VER_DROP;
	}

	result = filtering_and_updating(skb_in, tuple_in);
	if (result != VER_CONTINUE)
		return result;
	result = compute_out_tuple(tuple_in, &tuple_out, skb_in);
	if (result != VER_CONTINUE)
		return result;
	result = translating_the_packet(&tuple_out, skb_in, &skb_out);
	if (result != VER_CONTINUE)
		return result;
	result = sendpkt_send(skb_in, skb_out);
	if (result != VER_CONTINUE)
		return result;

	log_debug("Done step 5.");
	return VER_CONTINUE;
}
Exemple #2
0
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;
}
/**
 * Mirrors the core's behavior by processing skb_in as if it was the incoming packet.
 *
 * @param skb_in the outgoing packet. Except because it's a hairpin, here it's treated as if it was
 *		the one received from the network.
 * @param tuple_in skb_in's tuple.
 * @return whether we managed to U-turn the packet successfully.
 */
verdict handling_hairpinning(struct packet *in, struct tuple *tuple_in)
{
	struct packet out;
	struct tuple tuple_out;
	verdict result;

	log_debug("Step 5: Handling Hairpinning...");

	if (pkt_l4_proto(in) == L4PROTO_ICMP) {
		/*
		 * RFC 6146 section 2 (Definition of "Hairpinning").
		 *
		 * Update 2014-11-21:
		 * Actually, since ICMP errors count as UDP or TCP packets tuple-wise, maybe the RFC means
		 * we should only filter out ICMP echoes.
		 * Or maybe not even that, since they're going to be dropped later anyway, once Jool fails
		 * to find the mapping.
		 * Unfortunately, if I remove this if, Jool crashes when I hairpin a ICMP error.
		 */
		log_debug("ICMP is not supported by hairpinning. Dropping packet...");
		return VERDICT_DROP;
	}

	result = filtering_and_updating(in, tuple_in);
	if (result != VERDICT_CONTINUE)
		return result;
	result = compute_out_tuple(tuple_in, &tuple_out, in);
	if (result != VERDICT_CONTINUE)
		return result;
	result = translating_the_packet(&tuple_out, in, &out);
	if (result != VERDICT_CONTINUE)
		return result;
	result = sendpkt_send(in, &out);
	if (result != VERDICT_CONTINUE)
		return result;

	log_debug("Done step 5.");
	return VERDICT_CONTINUE;
}
static bool test_4to6(l4_protocol l4_proto)
{
	struct tuple in, out;
	int field = 0;
	bool success = true;

	if (is_error(init_ipv4_tuple(&in, remote4, 80, local4, 5678, l4_proto)))
		return false;

	success &= assert_equals_int(VER_CONTINUE, compute_out_tuple(&in, &out, NULL), "Call");
	success &= assert_equals_int(L3PROTO_IPV6, out.l3_proto, "l3 proto");
	success &= assert_equals_int(l4_proto, out.l4_proto, "l4 proto");
	success &= assert_equals_ipv6_str(local6, &out.src.addr6.l3, "src addr");
	if (l4_proto == L4PROTO_ICMP)
		success &= assert_equals_u16(1234, out.src.addr6.l4, "src port (icmp id)");
	else
		success &= assert_equals_u16(80, out.src.addr6.l4, "src port");
	success &= assert_equals_ipv6_str(remote6, &out.dst.addr6.l3, "dst addr");
	success &= assert_equals_u16(1234, out.dst.addr6.l4, "dst port");
	success &= assert_equals_int(0, field, "unchanged field");

	return success;
}