Ejemplo n.º 1
0
static verdict ipv4_icmp_err(struct sk_buff *skb, struct tuple *tuple4)
{
	struct iphdr *inner_ipv4 = (struct iphdr *) (icmp_hdr(skb) + 1);
	struct udphdr *inner_udp;
	struct tcphdr *inner_tcp;
	struct icmphdr *inner_icmp;

	tuple4->src.addr4.l3.s_addr = inner_ipv4->daddr;
	tuple4->dst.addr4.l3.s_addr = inner_ipv4->saddr;

	switch (inner_ipv4->protocol) {
	case IPPROTO_UDP:
		inner_udp = ipv4_extract_l4_hdr(inner_ipv4);
		tuple4->src.addr4.l4 = be16_to_cpu(inner_udp->dest);
		tuple4->dst.addr4.l4 = be16_to_cpu(inner_udp->source);
		tuple4->l4_proto = L4PROTO_UDP;
		break;

	case IPPROTO_TCP:
		inner_tcp = ipv4_extract_l4_hdr(inner_ipv4);
		tuple4->src.addr4.l4 = be16_to_cpu(inner_tcp->dest);
		tuple4->dst.addr4.l4 = be16_to_cpu(inner_tcp->source);
		tuple4->l4_proto = L4PROTO_TCP;
		break;

	case IPPROTO_ICMP:
		inner_icmp = ipv4_extract_l4_hdr(inner_ipv4);

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

		tuple4->src.addr4.l4 = be16_to_cpu(inner_icmp->un.echo.id);
		tuple4->dst.addr4.l4 = tuple4->src.addr4.l4;
		tuple4->l4_proto = L4PROTO_ICMP;
		break;

	default:
		log_debug("Packet's inner packet is not UDP, TCP or ICMP (%d)", inner_ipv4->protocol);
		inc_stats(skb, IPSTATS_MIB_INUNKNOWNPROTOS);
		return VER_DROP;
	}

	tuple4->l3_proto = L3PROTO_IPV4;

	return VER_CONTINUE;
}
Ejemplo n.º 2
0
static verdict ipv4_icmp_err(struct iphdr *hdr_ipv4, struct icmphdr *hdr_icmp, struct tuple *tuple)
{
	struct iphdr *inner_ipv4 = (struct iphdr *) (hdr_icmp + 1);
	struct udphdr *inner_udp;
	struct tcphdr *inner_tcp;
	struct icmphdr *inner_icmp;

	tuple->src.addr.ipv4.s_addr = inner_ipv4->daddr;
	tuple->dst.addr.ipv4.s_addr = inner_ipv4->saddr;

	switch (inner_ipv4->protocol) {
	case IPPROTO_UDP:
		inner_udp = ipv4_extract_l4_hdr(inner_ipv4);
		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 IPPROTO_TCP:
		inner_tcp = ipv4_extract_l4_hdr(inner_ipv4);
		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 IPPROTO_ICMP:
		inner_icmp = ipv4_extract_l4_hdr(inner_ipv4);

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

		tuple->src.l4_id = be16_to_cpu(inner_icmp->un.echo.id);
		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 ICMP (%d)", inner_ipv4->protocol);
		return VER_DROP;
	}

	tuple->l3_proto = L3PROTO_IPV4;

	return VER_CONTINUE;
}
Ejemplo n.º 3
0
static bool ipv4_validate_packet_len(struct sk_buff *skb_in, struct sk_buff *skb_out)
{
	struct iphdr *ip4_hdr = ip_hdr(skb_out);

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

	if (ip4_hdr->protocol == IPPROTO_ICMP) {
		struct icmphdr *icmp4_hdr = icmp_hdr(skb_out);
		if (is_icmp4_error(icmp4_hdr->type)) {
			int new_packet_len = skb_out->dev->mtu;

			skb_trim(skb_out, new_packet_len);

			ip4_hdr->tot_len = cpu_to_be16(new_packet_len);
			ip4_hdr->check = 0;
			ip4_hdr->check = ip_fast_csum(ip4_hdr, ip4_hdr->ihl);

			icmp4_hdr->checksum = 0;
			icmp4_hdr->checksum = ip_compute_csum(icmp4_hdr, new_packet_len - 4 * ip4_hdr->ihl);

			return true;
		}
	}

	if (is_dont_fragment_set(ip4_hdr)) {
		unsigned int ipv6_mtu = skb_in->dev->mtu;
		unsigned int ipv4_mtu = skb_out->dev->mtu;

		log_debug("Packet is too large for the outgoing MTU and the DF flag is set. Dropping...");
		icmpv6_send(skb_in, ICMPV6_PKT_TOOBIG, 0, cpu_to_be32(min_uint(ipv4_mtu, ipv6_mtu - 20)));
		return false;
	}

	/* The kernel will fragment it. */
	return true;
}
Ejemplo n.º 4
0
Archivo: packet.c Proyecto: NICMx/Jool
static bool has_inner_pkt4(__u8 icmp_type)
{
	return is_icmp4_error(icmp_type);
}
Ejemplo n.º 5
0
/**
 * Main F&U routine. Called during the processing of every packet.
 *
 * Decides if "skb" should be processed, updating binding and session information.
 *
 * @param[in] skb packet being translated.
 * @param[in] tuple skb's summary.
 * @return indicator of what should happen to skb.
 */
verdict filtering_and_updating(struct sk_buff* skb, struct tuple *in_tuple)
{
	struct ipv6hdr *hdr_ip6;
	verdict result = VER_CONTINUE;

	log_debug("Step 2: Filtering and Updating");

	switch (skb_l3_proto(skb)) {
	case L3PROTO_IPV6:
		/* ICMP errors should not be filtered or affect the tables. */
		if (skb_l4_proto(skb) == L4PROTO_ICMP && is_icmp6_error(icmp6_hdr(skb)->icmp6_type)) {
			log_debug("Packet is ICMPv6 error; skipping step...");
			return VER_CONTINUE;
		}
		/* Get rid of hairpinning loops and unwanted packets. */
		hdr_ip6 = ipv6_hdr(skb);
		if (pool6_contains(&hdr_ip6->saddr)) {
			log_debug("Hairpinning loop. Dropping...");
			inc_stats(skb, IPSTATS_MIB_INADDRERRORS);
			return VER_DROP;
		}
		if (!pool6_contains(&hdr_ip6->daddr)) {
			log_debug("Packet was rejected by pool6; dropping...");
			inc_stats(skb, IPSTATS_MIB_INADDRERRORS);
			return VER_DROP;
		}
		break;
	case L3PROTO_IPV4:
		/* ICMP errors should not be filtered or affect the tables. */
		if (skb_l4_proto(skb) == L4PROTO_ICMP && is_icmp4_error(icmp_hdr(skb)->type)) {
			log_debug("Packet is ICMPv4 error; skipping step...");
			return VER_CONTINUE;
		}
		/* Get rid of unexpected packets */
		if (!pool4_contains(ip_hdr(skb)->daddr)) {
			log_debug("Packet was rejected by pool4; dropping...");
			inc_stats(skb, IPSTATS_MIB_INADDRERRORS);
			return VER_DROP;
		}
		break;
	}

	/* Process packet, according to its protocol. */

	switch (skb_l4_proto(skb)) {
	case L4PROTO_UDP:
		switch (skb_l3_proto(skb)) {
		case L3PROTO_IPV6:
			result = ipv6_simple(skb, in_tuple);
			break;
		case L3PROTO_IPV4:
			result = ipv4_simple(skb, in_tuple);
			break;
		}
		break;

	case L4PROTO_TCP:
		result = tcp(skb, in_tuple);
		break;

	case L4PROTO_ICMP:
		switch (skb_l3_proto(skb)) {
		case L3PROTO_IPV6:
			if (filter_icmpv6_info()) {
				log_debug("Packet is ICMPv6 info (ping); dropping due to policy.");
				inc_stats(skb, IPSTATS_MIB_INDISCARDS);
				return VER_DROP;
			}

			result = ipv6_simple(skb, in_tuple);
			break;
		case L3PROTO_IPV4:
			result = ipv4_simple(skb, in_tuple);
			break;
		}
		break;
	}

	log_debug("Done: Step 2.");
	return result;
}
Ejemplo n.º 6
0
/**
 * Extracts relevant data from "skb" and stores it in the "tuple" tuple.
 *
 * @param skb packet the data will be extracted from.
 * @param tuple this function will populate this value using "skb"'s contents.
 * @return whether packet processing should continue.
 */
verdict determine_in_tuple(struct sk_buff *skb, struct tuple *in_tuple)
{
	struct icmphdr *icmp4;
	struct icmp6hdr *icmp6;
	verdict result = VER_CONTINUE;

	log_debug("Step 1: Determining the Incoming Tuple");

	switch (skb_l3_proto(skb)) {
	case L3PROTO_IPV4:
		switch (skb_l4_proto(skb)) {
		case L4PROTO_UDP:
			result = ipv4_udp(skb, in_tuple);
			break;
		case L4PROTO_TCP:
			result = ipv4_tcp(skb, in_tuple);
			break;
		case L4PROTO_ICMP:
			icmp4 = icmp_hdr(skb);
			if (is_icmp4_info(icmp4->type)) {
				result = ipv4_icmp_info(skb, in_tuple);
			} else if (is_icmp4_error(icmp4->type)) {
				result = ipv4_icmp_err(skb, in_tuple);
			} else {
				log_debug("Unknown ICMPv4 type: %u. Dropping packet...", icmp4->type);
				inc_stats(skb, IPSTATS_MIB_INHDRERRORS);
				result = VER_DROP;
			}
			break;
		}
		break;

	case L3PROTO_IPV6:
		switch (skb_l4_proto(skb)) {
		case L4PROTO_UDP:
			result = ipv6_udp(skb, in_tuple);
			break;
		case L4PROTO_TCP:
			result = ipv6_tcp(skb, in_tuple);
			break;
		case L4PROTO_ICMP:
			icmp6 = icmp6_hdr(skb);
			if (is_icmp6_info(icmp6->icmp6_type)) {
				result = ipv6_icmp_info(skb, in_tuple);
			} else if (is_icmp6_error(icmp6->icmp6_type)) {
				result = ipv6_icmp_err(skb, in_tuple);
			} else {
				log_debug("Unknown ICMPv6 type: %u. Dropping packet...", icmp6->icmp6_type);
				inc_stats(skb, IPSTATS_MIB_INHDRERRORS);
				result = VER_DROP;
			}
			break;
		}
		break;
	}

	/*
	 * We moved the transport-protocol-not-recognized ICMP errors to packet.c because they're
	 * covered in validations.
	 */

	log_tuple(in_tuple);
	log_debug("Done step 1.");
	return result;
}
Ejemplo n.º 7
0
/**
 * Extracts relevant data from "frag" and stores it in the "tuple" tuple.
 *
 * @param frag fragment the data will be extracted from. Whether the packet is fragmented or not,
 *		this has to be the chunk whose fragment offset is zero.
 * @param tuple this function will populate this value using "frag"'s contents.
 * @return whether packet processing should continue.
 */
verdict determine_in_tuple(struct fragment *frag, struct tuple *tuple)
{
	struct iphdr *hdr4;
	struct ipv6hdr *hdr6;
	struct icmphdr *icmp4;
	struct icmp6hdr *icmp6;
	verdict result = VER_CONTINUE;

	log_debug("Step 1: Determining the Incoming Tuple");

	switch (frag->l3_hdr.proto) {
	case L3PROTO_IPV4:
		hdr4 = frag_get_ipv4_hdr(frag);
		switch (frag->l4_hdr.proto) {
		case L4PROTO_UDP:
			result = ipv4_udp(hdr4, frag_get_udp_hdr(frag), tuple);
			break;
		case L4PROTO_TCP:
			result = ipv4_tcp(hdr4, frag_get_tcp_hdr(frag), tuple);
			break;
		case L4PROTO_ICMP:
			icmp4 = frag_get_icmp4_hdr(frag);
			if (is_icmp4_info(icmp4->type)) {
				result = ipv4_icmp_info(hdr4, icmp4, tuple);
			} else if (is_icmp4_error(icmp4->type)) {
				result = ipv4_icmp_err(hdr4, icmp4, tuple);
			} else {
				log_warning("Unknown ICMPv4 type: %u. Dropping packet...", icmp4->type);
				result = VER_DROP;
			}
			break;
		case L4PROTO_NONE:
			log_crit(ERR_ILLEGAL_NONE, "IPv4 - First fragment has no transport header.");
			result = VER_DROP;
		}
		break;

	case L3PROTO_IPV6:
		hdr6 = frag_get_ipv6_hdr(frag);
		switch (frag->l4_hdr.proto) {
		case L4PROTO_UDP:
			result = ipv6_udp(hdr6, frag_get_udp_hdr(frag), tuple);
			break;
		case L4PROTO_TCP:
			result = ipv6_tcp(hdr6, frag_get_tcp_hdr(frag), tuple);
			break;
		case L4PROTO_ICMP:
			icmp6 = frag_get_icmp6_hdr(frag);
			if (is_icmp6_info(icmp6->icmp6_type)) {
				result = ipv6_icmp_info(hdr6, icmp6, tuple);
			} else if (is_icmp6_error(icmp6->icmp6_type)) {
				result = ipv6_icmp_err(hdr6, icmp6, tuple);
			} else {
				log_warning("Unknown ICMPv6 type: %u. Dropping packet...", icmp6->icmp6_type);
				result = VER_DROP;
			}
			break;
		case L4PROTO_NONE:
			log_crit(ERR_ILLEGAL_NONE, "IPv6 - First fragment has no transport header.");
			result = VER_DROP;
		}
		break;
	}

	/*
	 * We moved the transport-protocol-not-recognized ICMP errors to fragment_db because they're
	 * covered in validations.
	 */

	log_tuple(tuple);
	log_debug("Done step 1.");
	return result;
}