Пример #1
0
static bool test_no_subheaders(void)
{
	// Init.
	struct ipv6hdr *ip6_header;
	unsigned char *payload;

	ip6_header = kmalloc(sizeof(struct ipv6hdr) + 4, GFP_ATOMIC);
	if (!ip6_header) {
		log_warning("Unable to allocate a test header.");
		return false;
	}
	ip6_header->nexthdr = NEXTHDR_UDP;

	payload = (unsigned char *) (ip6_header + 1);

	// Test next function.
	{
		struct hdr_iterator iterator = HDR_ITERATOR_INIT(ip6_header);
		ASSERT_EQUALS_PTR(ip6_header, iterator.data, "First header, data");
		ASSERT_EQUALS(-1, iterator.hdr_type, "First header, hdr type");

		hdr_iterator_next(&iterator);
		ASSERT_EQUALS_PTR(payload, iterator.data, "Payload 1st, data");
		ASSERT_EQUALS(NEXTHDR_UDP, iterator.hdr_type, "Payload 1st, hdr type");

		hdr_iterator_next(&iterator);
		ASSERT_EQUALS_PTR(payload, iterator.data, "Payload 2nd, data");
		ASSERT_EQUALS(NEXTHDR_UDP, iterator.hdr_type, "Payload 2nd, hdr type");

		hdr_iterator_next(&iterator);
		hdr_iterator_next(&iterator);
		hdr_iterator_next(&iterator);
		ASSERT_EQUALS_PTR(payload, iterator.data, "Payload 3rd, data");
		ASSERT_EQUALS(NEXTHDR_UDP, iterator.hdr_type, "Payload 3rd, hdr type");
	}

	// Test last function.
	{
		struct hdr_iterator iterator = HDR_ITERATOR_INIT(ip6_header);
		hdr_iterator_last(&iterator);
		ASSERT_EQUALS_PTR(payload, iterator.data, "Last function, data");
		ASSERT_EQUALS(NEXTHDR_UDP, iterator.hdr_type, "Last function, hdr type");
	}

	// Test get extension header function.
	{
		void *frag_hdr_computed = get_extension_header(ip6_header, NEXTHDR_FRAGMENT);
		void *hop_by_hop_hdr_computed = get_extension_header(ip6_header, NEXTHDR_HOP);
		void *udp_hdr_computed = get_extension_header(ip6_header, NEXTHDR_UDP);

		ASSERT_EQUALS_PTR(NULL, frag_hdr_computed, "Get function, frag hdr");
		ASSERT_EQUALS_PTR(NULL, hop_by_hop_hdr_computed, "Get function, hop-by-hop hdr");
		// Cause the UDP header is not an extension header.
		ASSERT_EQUALS_PTR(NULL, udp_hdr_computed, "Get function, payload");
	}

	return true;
}
Пример #2
0
/**
 * Initializes both "pipeline" and "in" using the data from "tuple", "skb", and the assumption that
 * we're translating from 6 to 4.
 * "pipeline" defines the sequence of functions that will be executed later and "in" is basically a
 * summary of "skb".
 */
static bool init_pipeline_ipv6(struct pipeline *pipeline, struct packet_in *in,
		struct nf_conntrack_tuple *tuple, struct sk_buff *skb)
{
	struct ipv6hdr *ip6_hdr = ipv6_hdr(skb);
	struct hdr_iterator iterator = HDR_ITERATOR_INIT(ip6_hdr);

	pipeline->l3_hdr_function = create_ipv4_hdr;
	pipeline->create_skb_function = create_skb;
	pipeline->l3_post_function = post_ipv4;

	in->packet = skb;
	in->tuple = tuple;

	in->l3_hdr = ip6_hdr;
	in->l3_hdr_type = IPPROTO_IPV6;
	in->l3_hdr_len = skb_transport_header(skb) - skb_network_header(skb);
	in->l3_hdr_basic_len = sizeof(*ip6_hdr);
	in->compute_l3_hdr_len = compute_ipv6_hdr_len;

	hdr_iterator_last(&iterator);
	if (iterator.hdr_type == NEXTHDR_AUTH || iterator.hdr_type == NEXTHDR_ESP) {
		// RFC 6146 section 5.1.
		log_warning("  Incoming IPv6 packet has an Auth header or an ESP header. Cannot translate; "
				"will drop the packet.");
		return false;
	}

	in->l4_hdr_type = iterator.hdr_type;
	switch (in->l4_hdr_type) {
	case NEXTHDR_TCP:
		in->l4_hdr_len = tcp_hdrlen(skb);
		pipeline->l4_post_function = post_tcp_ipv4;
		pipeline->l4_hdr_and_payload_function = copy_l4_hdr_and_payload;
		break;
	case NEXTHDR_UDP:
		in->l4_hdr_len = sizeof(struct udphdr);
		pipeline->l4_hdr_and_payload_function = copy_l4_hdr_and_payload;
		pipeline->l4_post_function = post_udp_ipv4;
		break;
	case NEXTHDR_ICMP:
		in->l4_hdr_len = sizeof(struct icmp6hdr);
		pipeline->l4_hdr_and_payload_function = create_icmp4_hdr_and_payload;
		pipeline->l4_post_function = post_icmp4;
		break;
	default:
		log_warning("  Unsupported l4 protocol (%d). Cannot translate.", in->l4_hdr_type);
		return false;
	}

	in->payload = iterator.data + in->l4_hdr_len;
	in->payload_len = be16_to_cpu(ip6_hdr->payload_len) //
			- (in->l3_hdr_len - sizeof(*ip6_hdr)) //
			- in->l4_hdr_len;

	return true;
}
Пример #3
0
static verdict ipv6_icmp_err(struct sk_buff *skb, struct tuple *tuple6)
{
	struct ipv6hdr *inner_ipv6 = (struct ipv6hdr *) (icmp6_hdr(skb) + 1);
	struct hdr_iterator iterator = HDR_ITERATOR_INIT(inner_ipv6);
	struct udphdr *inner_udp;
	struct tcphdr *inner_tcp;
	struct icmp6hdr *inner_icmp;

	tuple6->src.addr6.l3 = inner_ipv6->daddr;
	tuple6->dst.addr6.l3 = inner_ipv6->saddr;

	hdr_iterator_last(&iterator);
	switch (iterator.hdr_type) {
	case NEXTHDR_UDP:
		inner_udp = iterator.data;
		tuple6->src.addr6.l4 = be16_to_cpu(inner_udp->dest);
		tuple6->dst.addr6.l4 = be16_to_cpu(inner_udp->source);
		tuple6->l4_proto = L4PROTO_UDP;
		break;

	case NEXTHDR_TCP:
		inner_tcp = iterator.data;
		tuple6->src.addr6.l4 = be16_to_cpu(inner_tcp->dest);
		tuple6->dst.addr6.l4 = be16_to_cpu(inner_tcp->source);
		tuple6->l4_proto = L4PROTO_TCP;
		break;

	case NEXTHDR_ICMP:
		inner_icmp = iterator.data;

		if (is_icmp6_error(inner_icmp->icmp6_type)) {
			log_debug("Packet is a ICMP error containing a ICMP error.");
			inc_stats(skb, IPSTATS_MIB_INHDRERRORS);
			return VER_DROP;
		}

		tuple6->src.addr6.l4 = be16_to_cpu(inner_icmp->icmp6_dataun.u_echo.identifier);
		tuple6->dst.addr6.l4 = tuple6->src.addr6.l4;
		tuple6->l4_proto = L4PROTO_ICMP;
		break;

	default:
		log_debug("Packet's inner packet is not UDP, TCP or ICMPv6 (%d).", iterator.hdr_type);
		inc_stats(skb, IPSTATS_MIB_INUNKNOWNPROTOS);
		return VER_DROP;
	}

	tuple6->l3_proto = L3PROTO_IPV6;

	return VER_CONTINUE;
}
Пример #4
0
static bool ipv6_icmp_err(struct ipv6hdr *hdr_ipv6, struct icmp6hdr *hdr_icmp, struct tuple *tuple)
{
	struct ipv6hdr *inner_ipv6 = (struct ipv6hdr *) (hdr_icmp + 1);
	struct hdr_iterator iterator = HDR_ITERATOR_INIT(inner_ipv6);
	struct udphdr *inner_udp;
	struct tcphdr *inner_tcp;
	/* struct icmp6hdr *inner_icmp; */

	tuple->src.addr.ipv6 = inner_ipv6->daddr;
	tuple->dst.addr.ipv6 = inner_ipv6->saddr;

	hdr_iterator_last(&iterator);
	switch (iterator.hdr_type) {
	case IPPROTO_UDP:
		inner_udp = iterator.data;
		tuple->src.l4_id = be16_to_cpu(inner_udp->dest);
		tuple->dst.l4_id = be16_to_cpu(inner_udp->source);
		break;

	case IPPROTO_TCP:
		inner_tcp = iterator.data;
		tuple->src.l4_id = be16_to_cpu(inner_tcp->dest);
		tuple->dst.l4_id = be16_to_cpu(inner_tcp->source);
		break;

	case IPPROTO_ICMPV6:
		/* We're not supporting ICMP inside ICMP yet. */
		return false;

		/*
		inner_icmp = iterator.data;

		if (is_icmp6_error(inner_icmp->icmp6_type))
			return false;

		tuple->src.l4_id = be16_to_cpu(inner_icmp->icmp6_dataun.u_echo.identifier);
		tuple->dst.l4_id = tuple->src.l4_id;
		break;
		*/

	default:
		log_warning("Packet's inner packet is not UDP, TCP or ICMPv6 (%d).", iterator.hdr_type);
		return false;
	}

	tuple->l3_proto = PF_INET6;
	tuple->l4_proto = iterator.hdr_type;

	return true;
}
Пример #5
0
void *get_extension_header(struct ipv6hdr *ip6_hdr, __u8 hdr_id)
{
	struct hdr_iterator iterator = HDR_ITERATOR_INIT(ip6_hdr);

	if (!is_extension_hdr(hdr_id))
		return NULL;

	do {
		if (iterator.hdr_type == hdr_id)
			return iterator.data;
	} while (hdr_iterator_next(&iterator) == HDR_ITERATOR_SUCCESS);

	return NULL;
}
Пример #6
0
static verdict ipv6_icmp_err(struct ipv6hdr *hdr_ipv6, struct icmp6hdr *hdr_icmp,
		struct tuple *tuple)
{
	struct ipv6hdr *inner_ipv6 = (struct ipv6hdr *) (hdr_icmp + 1);
	struct hdr_iterator iterator = HDR_ITERATOR_INIT(inner_ipv6);
	struct udphdr *inner_udp;
	struct tcphdr *inner_tcp;
	struct icmp6hdr *inner_icmp;

	tuple->src.addr.ipv6 = inner_ipv6->daddr;
	tuple->dst.addr.ipv6 = inner_ipv6->saddr;

	hdr_iterator_last(&iterator);
	switch (iterator.hdr_type) {
	case NEXTHDR_UDP:
		inner_udp = iterator.data;
		tuple->src.l4_id = be16_to_cpu(inner_udp->dest);
		tuple->dst.l4_id = be16_to_cpu(inner_udp->source);
		tuple->l4_proto = L4PROTO_UDP;
		break;

	case NEXTHDR_TCP:
		inner_tcp = iterator.data;
		tuple->src.l4_id = be16_to_cpu(inner_tcp->dest);
		tuple->dst.l4_id = be16_to_cpu(inner_tcp->source);
		tuple->l4_proto = L4PROTO_TCP;
		break;

	case NEXTHDR_ICMP:
		inner_icmp = iterator.data;

		if (is_icmp6_error(inner_icmp->icmp6_type)) {
			log_debug("Packet is a ICMP error containing a ICMP error.");
			return VER_DROP;
		}

		tuple->src.l4_id = be16_to_cpu(inner_icmp->icmp6_dataun.u_echo.identifier);
		tuple->dst.l4_id = tuple->src.l4_id;
		tuple->l4_proto = L4PROTO_ICMP;
		break;

	default:
		log_warning("Packet's inner packet is not UDP, TCP or ICMPv6 (%d).", iterator.hdr_type);
		return VER_DROP;
	}

	tuple->l3_proto = L3PROTO_IPV6;

	return VER_CONTINUE;
}
Пример #7
0
/*
 * Size includes fragment header if packet is IPv6.
 */
static int net_hdr_size(void *pkt)
{
	struct hdr_iterator iterator = HDR_ITERATOR_INIT((struct ipv6hdr *) pkt);
	struct iphdr *hdr4 = pkt;

	switch (get_l3_proto(pkt)) {
	case 6:
		hdr_iterator_last(&iterator);
		return iterator.data - pkt;

	case 4:
		return (hdr4->ihl << 2);

	default:
		log_err("Invalid mode: %u", get_l3_proto(pkt));
		return -EINVAL;
	}
}
Пример #8
0
static bool ipv6_validate_packet_len(struct sk_buff *skb_in, struct sk_buff *skb_out)
{
	struct ipv6hdr *ip6_hdr = ipv6_hdr(skb_out);
	struct hdr_iterator iterator = HDR_ITERATOR_INIT(ip6_hdr);
	unsigned int ipv6_mtu;
	unsigned int ipv4_mtu;

	if (skb_out->len <= skb_out->dev->mtu)
		return true;

	hdr_iterator_last(&iterator);
	if (iterator.hdr_type == IPPROTO_ICMPV6) {
		struct icmp6hdr *icmpv6_hdr = icmp6_hdr(skb_out);
		if (is_icmp6_error(icmpv6_hdr->icmp6_type)) {
			int new_packet_len = skb_out->dev->mtu;
			int l3_payload_len = new_packet_len - (iterator.data - (void *) ip6_hdr);

			skb_trim(skb_out, new_packet_len);

			ip6_hdr->payload_len = cpu_to_be16(l3_payload_len);

			icmpv6_hdr->icmp6_cksum = 0;
			icmpv6_hdr->icmp6_cksum = csum_ipv6_magic(&ip6_hdr->saddr, &ip6_hdr->daddr,
					l3_payload_len, IPPROTO_ICMPV6, csum_partial(icmpv6_hdr, l3_payload_len, 0));

			return true;
		}
	}

	ipv6_mtu = skb_out->dev->mtu;
	ipv4_mtu = skb_in->dev->mtu;

	log_debug("Packet is too large for the outgoing MTU and IPv6 routers don't do fragmentation. "
			"Dropping...");
	icmp_send(skb_in, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
			cpu_to_be32(min_uint(ipv6_mtu, ipv4_mtu + 20)));
	return false;
}
Пример #9
0
static bool test_subheaders(void)
{
	// Init.
	const __u16 HOP_BY_HOP_HDR_LEN = 32;
	const __u16 ROUTING_HDR_LEN = 40;

	struct ipv6hdr *ip6_header;
	struct frag_hdr *fragment_hdr;
	struct ipv6_opt_hdr *hop_by_hop_hdr;
	struct ipv6_opt_hdr *routing_hdr;
	unsigned char *payload;

	ip6_header = kmalloc(sizeof(struct ipv6hdr)
				+ sizeof(struct frag_hdr)
				+ HOP_BY_HOP_HDR_LEN
				+ ROUTING_HDR_LEN
				+ 4, // (payload.)
				GFP_ATOMIC);
	if (!ip6_header) {
		log_warning("Unable to allocate a test header.");
		return false;
	}
	ip6_header->nexthdr = NEXTHDR_FRAGMENT;

	fragment_hdr = (struct frag_hdr *) (ip6_header + 1);
	fragment_hdr->nexthdr = NEXTHDR_HOP;

	hop_by_hop_hdr = (struct ipv6_opt_hdr *) (fragment_hdr + 1);
	hop_by_hop_hdr->nexthdr = NEXTHDR_ROUTING;
	hop_by_hop_hdr->hdrlen = (HOP_BY_HOP_HDR_LEN / 8) - 1;

	routing_hdr = ((void *) hop_by_hop_hdr) + HOP_BY_HOP_HDR_LEN;
	routing_hdr->nexthdr = NEXTHDR_UDP;
	routing_hdr->hdrlen = (ROUTING_HDR_LEN / 8) - 1;

	payload = ((void *) routing_hdr) + ROUTING_HDR_LEN;

	// Test next function.
	{
		struct hdr_iterator next_iterator = HDR_ITERATOR_INIT(ip6_header);
		ASSERT_EQUALS_PTR(ip6_header, next_iterator.data, "First (main) header, data");
		ASSERT_EQUALS(-1, next_iterator.hdr_type, "First (main) header, hdr type");

		hdr_iterator_next(&next_iterator);
		ASSERT_EQUALS_PTR(fragment_hdr, next_iterator.data, "Second (frag) header, data");
		ASSERT_EQUALS(NEXTHDR_FRAGMENT, next_iterator.hdr_type, "Second (frag) header, hdr type");

		hdr_iterator_next(&next_iterator);
		ASSERT_EQUALS_PTR(hop_by_hop_hdr, next_iterator.data, "Third (hop-by-hop) header, data");
		ASSERT_EQUALS(NEXTHDR_HOP, next_iterator.hdr_type, "Third (hop-by-hop) header, hdr type");

		hdr_iterator_next(&next_iterator);
		ASSERT_EQUALS_PTR(routing_hdr, next_iterator.data, "Fourth (Routing) header, data");
		ASSERT_EQUALS(NEXTHDR_ROUTING, next_iterator.hdr_type, "Fourth (Routing) header, hdr type");

		hdr_iterator_next(&next_iterator);
		ASSERT_EQUALS_PTR(payload, next_iterator.data, "Payload 1st, data");
		ASSERT_EQUALS(NEXTHDR_UDP, next_iterator.hdr_type, "Payload 1st, hdr type");

		hdr_iterator_next(&next_iterator);
		ASSERT_EQUALS_PTR(payload, next_iterator.data, "Payload 2nd, data");
		ASSERT_EQUALS(NEXTHDR_UDP, next_iterator.hdr_type, "Payload 2nd, hdr type");
	}

	// Test last function.
	{
		struct hdr_iterator last_iterator = HDR_ITERATOR_INIT(ip6_header);
		hdr_iterator_init(&last_iterator, ip6_header);
		hdr_iterator_last(&last_iterator);
		ASSERT_EQUALS_PTR(payload, last_iterator.data, "Last function, data");
		ASSERT_EQUALS(NEXTHDR_UDP, last_iterator.hdr_type, "Last function, hdr type");
	}

	// Test get extension header function.
	{
		void *frag_hdr_computed = get_extension_header(ip6_header, NEXTHDR_FRAGMENT);
		void *hop_by_hop_hdr_computed = get_extension_header(ip6_header, NEXTHDR_HOP);
		void *udp_hdr_computed = get_extension_header(ip6_header, NEXTHDR_UDP);

		ASSERT_EQUALS_PTR(fragment_hdr, frag_hdr_computed, "Get function, frag hdr");
		ASSERT_EQUALS_PTR(hop_by_hop_hdr, hop_by_hop_hdr_computed, "Get function, hop-by-hop hdr");
		// Cause the UDP header is not an extension header.
		ASSERT_EQUALS_PTR(NULL, udp_hdr_computed, "Get function, payload");
	}

	return true;
}
Пример #10
0
void hdr_iterator_init(struct hdr_iterator *iterator, struct ipv6hdr *main_hdr)
{
	struct hdr_iterator defaults = HDR_ITERATOR_INIT(main_hdr);
	memcpy(iterator, &defaults, sizeof(defaults));
}
Пример #11
0
/**
 * Assumes that "l3_hdr" points to a ipv6hdr, and returns its size, extension headers included.
 */
static __u16 compute_ipv6_hdr_len(void *l3_hdr)
{
	struct hdr_iterator iterator = HDR_ITERATOR_INIT((struct ipv6hdr *) l3_hdr);
	hdr_iterator_last(&iterator);
	return iterator.data - l3_hdr;
}