Пример #1
0
bool validate_frag_hdr(struct frag_hdr *hdr, u16 frag_offset, u16 mf, __u8 nexthdr)
{
    bool success = true;

    success &= assert_equals_u8(nexthdr, hdr->nexthdr, "Fraghdr-nexthdr");
    success &= assert_equals_u8(0, hdr->reserved, "Fraghdr-nexthdr");
    success &= assert_equals_u16(frag_offset, get_fragment_offset_ipv6(hdr), "Fraghdr-frag offset");
    success &= assert_equals_u16(mf, is_more_fragments_set_ipv6(hdr), "Fraghdr-MF");
    success &= assert_equals_u16(4321, be32_to_cpu(hdr->identification), "Fraghdr-ID");

    return success;
}
Пример #2
0
/**
 * Groups "skb_in" with the rest of its fragments.
 * If the rest of the fragments have not yet arrived, this will return VER_STOLEN and store skb_in.
 * If all of the fragments have arrived, this will return VER_CONTINUE and the zero-offset fragment
 * will be returned in "skb_out". The rest of the fragments can be accesed via skb_out's list
 * (skb_shinfo(skb_out)->frag_list).
 */
verdict fragdb_handle(struct packet *pkt)
{
	/* The fragment collector skb belongs to. */
	struct reassembly_buffer *buffer;
	struct frag_hdr *hdr_frag = pkt_frag_hdr(pkt);
	int error;

	if (!is_fragmented_ipv6(hdr_frag))
		return VERDICT_CONTINUE;

	/*
	 * Because the packet *is* fragmented, we know we're being compiled in kernel 3.12 or lower at
	 * this point.
	 * (Other defragmenters conceal the fragment header, effectively pretending there's no
	 * fragmentation.)
	 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
	WARN(true, "This code is supposed to be unreachable in kernels 3.13+! Please report.");
	return VERDICT_DROP;
#endif

	log_debug("Adding fragment to database.");

	error = validate_skb(pkt->skb);
	if (error)
		return VERDICT_DROP;

	spin_lock_bh(&table_lock);

	buffer = add_pkt(pkt);
	if (!buffer) {
		spin_unlock_bh(&table_lock);
		return VERDICT_DROP;
	}

	/*
	 * nf_defrag_ipv6 is supposed to sort the fragments, so this condition should be all we need
	 * to figure out whether we have all the fragments.
	 * Otherwise we'd need to keep track of holes. If you ever find yourself needing to add hole
	 * logic, keep in mind that this module used to do that in Jool 3.2, so you might be able
	 * to reuse it.
	 */
	if (is_more_fragments_set_ipv6(hdr_frag)) {
		spin_unlock_bh(&table_lock);
		return VERDICT_STOLEN;
	}

	*pkt = buffer->pkt;
	pkt->original_pkt = pkt;
	buffer->pkt.skb = NULL;
	/* Note, at this point, buffer->pkt is invalid. Do not use. */
	buffer_destroy(buffer, pkt);
	spin_unlock_bh(&table_lock);

	if (!skb_make_writable(pkt->skb, pkt_l3hdr_len(pkt)))
		return VERDICT_DROP;
	/* Why this? Dunno, both defrags do it when they support frag_list. */
	pkt_ip6_hdr(pkt)->payload_len = cpu_to_be16(pkt->skb->len - sizeof(struct ipv6hdr));
	/*
	 * The kernel's defrag also removes the fragment header.
	 * That actually harms us, so we don't mirror it. Instead, we make the fragment atomic.
	 * The rest of Jool must assume the packet might have a redundant fragment header.
	 */
	pkt_frag_hdr(pkt)->frag_off &= cpu_to_be16(~IP6_MF);

	log_debug("All the fragments are now available. Resuming translation...");
	return VERDICT_CONTINUE;
}