示例#1
0
static bool test_compare_addr4(void)
{
	struct bib_entry *bib;
	struct in_addr addr4;
	bool success = true;

	bib = bib_create_str("1::1", 1111, "1.1.1.1", 1111, L4PROTO_TCP);
	if (!bib)
		return false;

	if (str_to_addr4("2.2.2.2", &addr4) != 0)
		goto fail;
	success &= assert_true(compare_addr4(bib, &addr4) < 0, "< 0");
	if (str_to_addr4("1.1.1.1", &addr4) != 0)
		goto fail;
	success &= assert_true(compare_addr4(bib, &addr4) == 0, "= 0");
	if (str_to_addr4("0.0.0.0", &addr4) != 0)
		goto fail;
	success &= assert_true(compare_addr4(bib, &addr4) > 0, "> 0");

	bib_kfree(bib);
	return success;

fail:
	bib_kfree(bib);
	return false;
}
示例#2
0
static bool test_compare_full6(void)
{
	struct bib_entry *bib;
	struct ipv6_transport_addr taddr6;
	bool success = true;

	bib = bib_create_str("1::1", 1111, "1.1.1.1", 1111, L4PROTO_TCP);
	if (!bib)
		return false;

	if (str_to_addr6("2::2", &taddr6.l3) != 0)
		goto fail;
	taddr6.l4 = 1111;
	success &= assert_true(compare_full6(bib, &taddr6) < 0, "<< 0");
	if (str_to_addr6("1::1", &taddr6.l3) != 0)
		goto fail;
	taddr6.l4 = 1112;
	success &= assert_true(compare_full6(bib, &taddr6) < 0, "< 0");
	taddr6.l4 = 1111;
	success &= assert_true(compare_full6(bib, &taddr6) == 0, "= 0");
	taddr6.l4 = 1110;
	success &= assert_true(compare_full6(bib, &taddr6) > 0, "> 0");
	if (str_to_addr6("0::0", &taddr6.l3) != 0)
		goto fail;
	taddr6.l4 = 1111;
	success &= assert_true(compare_full6(bib, &taddr6) > 0, ">> 0");

	bib_kfree(bib);
	return success;

fail:
	bib_kfree(bib);
	return false;
}
示例#3
0
/**
 * Inserts a single entry, validates it, removes it, validates again.
 * Does not touch the session tables.
 */
static bool simple_bib(void)
{
	struct ipv4_transport_addr addr = addr4[0];
	struct bib_entry *bib;
	bool success = true;

	if (is_error(pool4_get_any_port(L4PROTO_TCP, &addr.l3, &addr.l4)))
		return false;

	bib = bib_create(&addr, &addr6[0], false, L4PROTO_TCP);
	if (!assert_not_null(bib, "Allocation of test BIB entry"))
		return false;

	success &= assert_equals_int(0, bibdb_add(bib), "BIB insertion call");
	success &= assert_bib("BIB insertion state", bib, false, true, false);
	if (!success)
		return false;

	success &= assert_equals_int(0, bibdb_remove(bib, false), "BIB removal call");
	success &= assert_bib("BIB removal state", bib, false, false, false);
	if (!success)
		return false;

	bib_kfree(bib);
	return success;
}
static bool add_bib(struct in_addr *ip4_addr, __u16 ip4_port, struct in6_addr *ip6_addr,
		__u16 ip6_port, l4_protocol l4_proto)
{
	struct bib_entry *bib;
	struct ipv6_tuple_address addr6;
	struct ipv4_tuple_address addr4;

	/* Generate the BIB. */
	addr4.address = *ip4_addr;
	addr4.l4_id = ip4_port;
	addr6.address = *ip6_addr;
	addr6.l4_id = ip6_port;

	bib = bib_create(&addr4, &addr6, false);
	if (!bib) {
		log_warning("Can't allocate a BIB entry!");
		return false;
	}

	/*
	log_debug("BIB [%pI4#%u, %pI6c#%u]",
			&bib->ipv4.address, bib->ipv4.l4_id,
			&bib->ipv6.address, bib->ipv6.l4_id);
	*/

	/* Add it to the table. */
	if (is_error(bib_add(bib, l4_proto))) {
		log_warning("Can't add the dummy BIB to the table.");
		bib_kfree(bib);
		return false;
	}

	return true;
}
示例#5
0
int add_static_route(struct request_bib *req)
{
	struct bib_entry *bib = NULL;
	int error;

	error = pool4_get(req->l4_proto, &req->add.addr4);
	if (error) {
		log_err("The IPv4 address and port could not be reserved from the pool. "
				"Maybe the IPv4 address you provided does not belong to the pool. "
				"Or maybe they're being used by some other BIB entry?");
		return error;
	}

	bib = bib_create(&req->add.addr4, &req->add.addr6, true, req->l4_proto);
	if (!bib) {
		log_err("Could not allocate the BIB entry.");
		error = -ENOMEM;
		goto bib_error;
	}

	error = bibdb_add(bib);
	if (error) {
		log_err("The BIB entry could not be added to the database. Maybe an entry with the "
				"same IPv4 and/or IPv6 transport address already exists?");
		bib_kfree(bib);
		goto bib_error;
	}

	/*
	 * We do not call bib_return(bib) here, because we want the entry to hold a fake user so the
	 * timer doesn't delete it.
	 */

	return 0;

bib_error:
	pool4_return(req->l4_proto, &req->add.addr4);
	return error;
}
static bool test_hairpin(l4_protocol l4_proto, skb_creator create_skb_fn)
{
	struct sk_buff *skb_in = NULL;
	struct sk_buff *skb_out = NULL;
	struct sk_buff *skb_tmp = NULL;
	struct bib_entry *static_bib = NULL;
	struct bib_entry *dynamic_bib = NULL;
	struct session_entry *static_session = NULL;
	struct session_entry *dynamic_session = NULL;
	struct tuple tuple6;
	bool success = true;

	static_bib = bib_create_str(SERVER_ADDR6, SERVER_PORT6,
			NAT64_POOL4, SERVER_PORT6,
			l4_proto);
	dynamic_bib = bib_create_str(CLIENT_ADDR, CLIENT_PORT,
			NAT64_POOL4, DYNAMIC_BIB_IPV4_PORT,
			l4_proto);
	static_session = session_create_str(
			SERVER_ADDR6, SERVER_PORT6,
			SERVER_HAIRPIN_ADDR, DYNAMIC_BIB_IPV4_PORT,
			NAT64_POOL4, SERVER_PORT6,
			NAT64_POOL4, DYNAMIC_BIB_IPV4_PORT,
			l4_proto);
	dynamic_session = session_create_str(CLIENT_ADDR, CLIENT_PORT,
			SERVER_HAIRPIN_ADDR, SERVER_PORT6,
			NAT64_POOL4, DYNAMIC_BIB_IPV4_PORT,
			NAT64_POOL4, SERVER_PORT6,
			l4_proto);

	if (!static_bib || !dynamic_bib || !static_session || !dynamic_session)
		goto fail;

	/* Send the request. */
	if (is_error(init_ipv6_tuple(&tuple6,
			CLIENT_ADDR, CLIENT_PORT,
			SERVER_HAIRPIN_ADDR, SERVER_PORT6,
			l4_proto)))
		goto fail;
	if (is_error(create_skb_fn(&tuple6, &skb_in, 40, 32)))
		goto fail;

	success &= send(skb_in);
	success &= BIB_ASSERT(l4_proto, static_bib, dynamic_bib);
	success &= SESSION_ASSERT(l4_proto, static_session, dynamic_session);

	skb_out = skb_tmp = get_sent_skb();
	success &= assert_not_null(skb_out, "Request packet");
	if (!success)
		goto fail;

	do {
		success &= assert_equals_ipv6_str(SERVER_HAIRPIN_ADDR, &ipv6_hdr(skb_tmp)->saddr, "out src");
		success &= assert_equals_ipv6_str(SERVER_ADDR6, &ipv6_hdr(skb_tmp)->daddr, "out dst");
		skb_tmp = skb_tmp->next;
	} while (skb_tmp);
	switch (l4_proto) {
	case L4PROTO_UDP:
		success &= assert_equals_u16(DYNAMIC_BIB_IPV4_PORT,
				be16_to_cpu(udp_hdr(skb_out)->source),
				"out's src port");
		success &= assert_equals_u16(SERVER_PORT6,
				be16_to_cpu(udp_hdr(skb_out)->dest),
				"out's dst port");
		break;
	case L4PROTO_TCP:
		success &= assert_equals_u16(DYNAMIC_BIB_IPV4_PORT,
				be16_to_cpu(tcp_hdr(skb_out)->source),
				"out's src port");
		success &= assert_equals_u16(SERVER_PORT6,
				be16_to_cpu(tcp_hdr(skb_out)->dest),
				"out's dst port");
		break;
	case L4PROTO_ICMP:
	case L4PROTO_OTHER:
		log_err("Test is not designed for protocol %d.", l4_proto);
		success = false;
		break;
	}

	if (!success)
		goto fail;

	kfree_skb(skb_out);

	/* Send the response. */
	if (is_error(init_ipv6_tuple(&tuple6,
			SERVER_ADDR6, SERVER_PORT6,
			SERVER_HAIRPIN_ADDR, DYNAMIC_BIB_IPV4_PORT,
			l4_proto)))
		goto fail;
	if (is_error(create_skb_fn(&tuple6, &skb_in, 100, 32)))
		goto fail;

	success &= send(skb_in);
	/* The module should have reused the entries, so the database shouldn't have changed. */
	success &= BIB_ASSERT(l4_proto, static_bib, dynamic_bib);
	success &= SESSION_ASSERT(l4_proto, static_session, dynamic_session);

	skb_out = skb_tmp = get_sent_skb();
	success &= assert_not_null(skb_out, "Response packet");
	if (!success)
		goto fail;

	do {
		success &= assert_equals_ipv6_str(SERVER_HAIRPIN_ADDR, &ipv6_hdr(skb_out)->saddr, "out src");
		success &= assert_equals_ipv6_str(CLIENT_ADDR, &ipv6_hdr(skb_out)->daddr, "out dst");
		skb_tmp = skb_tmp->next;
	} while (skb_tmp);
	switch (l4_proto) {
	case L4PROTO_UDP:
		success &= assert_equals_u16(SERVER_PORT6,
				be16_to_cpu(udp_hdr(skb_out)->source),
				"out's src port");
		success &= assert_equals_u16(CLIENT_PORT,
				be16_to_cpu(udp_hdr(skb_out)->dest),
				"out's dst port");
		break;
	case L4PROTO_TCP:
		success &= assert_equals_u16(SERVER_PORT6,
				be16_to_cpu(tcp_hdr(skb_out)->source),
				"out's src port");
		success &= assert_equals_u16(CLIENT_PORT,
				be16_to_cpu(tcp_hdr(skb_out)->dest),
				"out's dst port");
		break;
	case L4PROTO_ICMP:
	case L4PROTO_OTHER:
		log_err("Test is not designed for protocol %d.", l4_proto);
		success = false;
		break;
	}

	kfree_skb(skb_out);
	session_return(dynamic_session);
	session_return(static_session);
	bib_kfree(dynamic_bib);
	bib_kfree(static_bib);
	return success;

fail:
	kfree_skb(skb_out);
	if (dynamic_session)
		session_return(dynamic_session);
	if (static_session)
		session_return(static_session);
	if (dynamic_bib)
		bib_kfree(dynamic_bib);
	if (static_bib)
		bib_kfree(static_bib);

	return false;
}
示例#7
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;
}
示例#8
0
int delete_static_route(struct request_bib *req)
{
	struct bib_entry *bib;
	struct session_entry *session;
	int error = 0;

	spin_lock_bh(&bib_session_lock);

	switch (req->remove.l3_proto) {
	case L3PROTO_IPV6:
		error = bib_get_by_ipv6(&req->remove.ipv6, req->l4_proto, &bib);
		if (error)
			goto end;
		break;
	case L3PROTO_IPV4:
		error = bib_get_by_ipv4(&req->remove.ipv4, req->l4_proto, &bib);
		if (error)
			goto end;
		break;
	default:
		log_err(ERR_L3PROTO, "Unsupported network protocol: %u.", req->remove.l3_proto);
		error = -EINVAL;
		goto end;
	}

	if (!bib) {
		log_err(ERR_BIB_NOT_FOUND, "Could not find the BIB entry requested by the user.");
		error = -ENOENT;
		goto end;
	}

	/*
	 * I'm tempted to assert that the entry is static here. Would that serve a purpose?
	 * Nah.
	 */

	while (!list_empty(&bib->sessions)) {
		session = container_of(bib->sessions.next, struct session_entry, bib_list_hook);
		error = session_remove(session);
		if (error) {
			log_err(ERR_UNKNOWN_ERROR,
					"Session [%pI6c#%u, %pI6c#%u, %pI4#%u, %pI4#%u] refused to die.",
					&session->ipv6.remote.address, session->ipv6.remote.l4_id,
					&session->ipv6.local.address, session->ipv6.local.l4_id,
					&session->ipv4.local.address, session->ipv4.local.l4_id,
					&session->ipv4.remote.address, session->ipv4.remote.l4_id);
			goto end;
		}
		list_del(&session->bib_list_hook);
		list_del(&session->expire_list_hook);
		session_kfree(session);
	}

	error = bib_remove(bib, req->l4_proto);
	if (error) {
		log_err(ERR_UNKNOWN_ERROR, "Remove bib entry call ended with error code %d, "
				"despite validations.", error);
		goto end;
	}

	pool4_return(req->l4_proto, &bib->ipv4);
	bib_kfree(bib);
	/* Fall through. */

end:
	spin_unlock_bh(&bib_session_lock);
	return error;
}