Пример #1
0
unsigned int core_4to6(struct sk_buff *skb)
{
	struct packet pkt;
	struct iphdr *hdr = ip_hdr(skb);
	int error;

	if (config_get_is_disable())
		return NF_ACCEPT; /* Translation is disabled; let the packet pass. */

	if (is_blacklisted4(hdr->saddr) || is_blacklisted4(hdr->daddr))
		return NF_ACCEPT;

	if (nat64_is_stateful()) {
		if (!pool4_contains(hdr->daddr) || pool6_is_empty())
			return NF_ACCEPT; /* Not meant for translation; let the kernel handle it. */
	}

	log_debug("===============================================");
	log_debug("Catching IPv4 packet: %pI4->%pI4", &hdr->saddr, &hdr->daddr);

	error = pkt_init_ipv4(&pkt, skb); /* Reminder: This function might change pointers. */
	if (error)
		return NF_DROP;

	error = validate_icmp4_csum(&pkt);
	if (error) {
		inc_stats(&pkt, IPSTATS_MIB_INHDRERRORS);
		return NF_DROP;
	}

	return core_common(&pkt);
}
Пример #2
0
unsigned int core_4to6(struct sk_buff *skb)
{
	struct iphdr *ip4_header;
	struct in_addr daddr;
	enum verdict result;

	skb_linearize(skb);

	ip4_header = ip_hdr(skb);

	daddr.s_addr = ip4_header->daddr;
	if (!pool4_contains(&daddr))
		return NF_ACCEPT;

	log_debug("===============================================");
	log_debug("Catching IPv4 packet: %pI4->%pI4", &ip4_header->saddr, &ip4_header->daddr);

	result = validate_skb_ipv4(skb);
	if (result != VER_CONTINUE)
		return result;

	return nat64_core(skb,
			compute_out_tuple_4to6,
			translating_the_packet_4to6,
			send_packet_ipv6);
}
Пример #3
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 packet *pkt, struct tuple *in_tuple)
{
	struct ipv6hdr *hdr_ip6;
	verdict result = VERDICT_CONTINUE;

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

	switch (pkt_l3_proto(pkt)) {
	case L3PROTO_IPV6:
		/* ICMP errors should not be filtered or affect the tables. */
		if (pkt_is_icmp6_error(pkt)) {
			log_debug("Packet is ICMPv6 error; skipping step...");
			return VERDICT_CONTINUE;
		}
		/* Get rid of hairpinning loops and unwanted packets. */
		hdr_ip6 = pkt_ip6_hdr(pkt);
		if (pool6_contains(&hdr_ip6->saddr)) {
			log_debug("Hairpinning loop. Dropping...");
			inc_stats(pkt, IPSTATS_MIB_INADDRERRORS);
			return VERDICT_DROP;
		}
		if (!pool6_contains(&hdr_ip6->daddr)) {
			log_debug("Packet was rejected by pool6; dropping...");
			inc_stats(pkt, IPSTATS_MIB_INADDRERRORS);
			return VERDICT_DROP;
		}
		break;
	case L3PROTO_IPV4:
		/* ICMP errors should not be filtered or affect the tables. */
		if (pkt_is_icmp4_error(pkt)) {
			log_debug("Packet is ICMPv4 error; skipping step...");
			return VERDICT_CONTINUE;
		}
		/* Get rid of unexpected packets */
		if (!pool4_contains(pkt_ip4_hdr(pkt)->daddr)) {
			log_debug("Packet was rejected by pool4; dropping...");
			inc_stats(pkt, IPSTATS_MIB_INADDRERRORS);
			return VERDICT_DROP;
		}
		break;
	}

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

	switch (pkt_l4_proto(pkt)) {
	case L4PROTO_UDP:
		switch (pkt_l3_proto(pkt)) {
		case L3PROTO_IPV6:
			result = ipv6_simple(pkt, in_tuple);
			break;
		case L3PROTO_IPV4:
			result = ipv4_simple(pkt, in_tuple);
			break;
		}
		break;

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

	case L4PROTO_ICMP:
		switch (pkt_l3_proto(pkt)) {
		case L3PROTO_IPV6:
			if (config_get_filter_icmpv6_info()) {
				log_debug("Packet is ICMPv6 info (ping); dropping due to policy.");
				inc_stats(pkt, IPSTATS_MIB_INDISCARDS);
				return VERDICT_DROP;
			}

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

	case L4PROTO_OTHER:
		WARN(true, "Unknown layer 4 protocol (%d)...", pkt_l4_proto(pkt));
		break;
	}

	log_debug("Done: Step 2.");
	return result;
}
Пример #4
0
/**
 * Checks whether "pkt" is a hairpin packet.
 *
 * @param pkt outgoing packet the NAT64 would send if it's not a hairpin.
 * @return whether pkt is a hairpin packet.
 */
bool is_hairpin(struct packet *pkt)
{
	return (pkt_l3_proto(pkt) == L3PROTO_IPV4) ? pool4_contains(pkt_ip4_hdr(pkt)->daddr) : false;
}
Пример #5
0
int add_static_route(struct request_bib *req)
{
	struct bib_entry *bib_by_ipv6, *bib_by_ipv4;
	struct bib_entry *bib = NULL;
	int error;

	if (!pool4_contains(&req->add.ipv4.address)) {
		log_err(ERR_POOL6_NOT_FOUND, "The address '%pI4' does not belong to the IPv4 pool.",
				&req->add.ipv4.address);
		return -EINVAL;
	}

	spin_lock_bh(&bib_session_lock);

	/* Check if the BIB entry exists. */
	error = bib_get_by_ipv6(&req->add.ipv6, req->l4_proto, &bib_by_ipv6);
	if (!error) {
		bib = bib_by_ipv6;
		goto already_mapped;
	}
	if (error != -ENOENT)
		goto generic_error;

	error = bib_get_by_ipv4(&req->add.ipv4, req->l4_proto, &bib_by_ipv4);
	if (!error) {
		bib = bib_by_ipv4;
		goto already_mapped;
	}
	if (error != -ENOENT)
		goto generic_error;

	/* Borrow the address and port from the IPv4 pool. */
	if (is_error(pool4_get(req->l4_proto, &req->add.ipv4))) {
		/*
		 * This might happen if Filtering just reserved the address#port, but hasn't yet inserted
		 * the BIB entry to the table. This is because bib_session_lock doesn't cover the IPv4
		 * pool.
		 * Otherwise something's not returning borrowed address#ports to the pool, which is an
		 * error.
		 */
		log_err(ERR_BIB_REINSERT, "Port number %u from address %pI4 is taken from the IPv4 pool, "
				"but it wasn't found in the BIB. Please try again; if the problem persists, "
				"please report.", req->add.ipv4.l4_id, &req->add.ipv4.address);
		error = -EEXIST;
		goto failure;
	}

	/* Create and insert the entry. */
	bib = bib_create(&req->add.ipv4, &req->add.ipv6, true);
	if (!bib) {
		log_err(ERR_ALLOC_FAILED, "Could NOT allocate a BIB entry.");
		error = -ENOMEM;
		goto failure;
	}

	error = bib_add(bib, req->l4_proto);
	if (error) {
		log_err(ERR_UNKNOWN_ERROR, "Could NOT add the BIB entry to the table.");
		goto failure;
	}

	spin_unlock_bh(&bib_session_lock);
	return 0;

already_mapped:
	log_err(ERR_BIB_REINSERT, "%pI6c#%u is already mapped to %pI4#%u.",
			&bib->ipv6.address, bib->ipv6.l4_id,
			&bib->ipv4.address, bib->ipv4.l4_id);
	error = -EEXIST;
	bib = NULL;
	goto failure;

generic_error:
	log_err(ERR_UNKNOWN_ERROR, "Error code %u while trying to interact with the BIB.",
			error);
	/* Fall through. */

failure:
	if (bib)
		bib_kfree(bib);
	spin_unlock_bh(&bib_session_lock);
	return error;
}
Пример #6
0
/**
 * Checks whether "pkt" is a hairpin packet.
 *
 * @param pkt outgoing packet the NAT64 would send if it's not a hairpin.
 * @return whether pkt is a hairpin packet.
 */
bool is_hairpin(struct sk_buff *skb)
{
	return (skb_l3_proto(skb) == L3PROTO_IPV4) ? pool4_contains(ip_hdr(skb)->daddr) : false;
}
Пример #7
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;
}