Example #1
0
static bool test_6to4(l4_protocol l4_proto,
		int (*create_skb6_fn)(struct tuple *, struct sk_buff **, u16, u8),
		int (*create_skb4_fn)(struct tuple *, struct sk_buff **, u16, u8),
		u16 expected_payload4_len)
{
	struct sk_buff *skb6 = NULL, *skb4_expected = NULL, *skb4_actual = NULL;
	struct tuple tuple6, tuple4;
	bool result = false;

	if (init_ipv6_tuple(&tuple6, "1::1", 50080, "64::192.0.2.5", 51234, L4PROTO_UDP) != 0
			|| init_ipv4_tuple(&tuple4, "192.0.2.2", 80, "192.0.2.5", 1234, L4PROTO_UDP) != 0
			|| create_skb6_fn(&tuple6, &skb6, 100, 32) != 0
			|| create_skb4_fn(&tuple4, &skb4_expected, expected_payload4_len, 31) != 0)
		goto end;

	if (translating_the_packet(&tuple4, skb6, &skb4_actual) != VER_CONTINUE)
		goto end;

	result = compare_skbs(skb4_expected, skb4_actual);
	/* Fall through. */

end:
	kfree_skb(skb6);
	kfree_skb(skb4_expected);
	kfree_skb(skb4_actual);
	return result;
}
Example #2
0
int create_tcp_packet(struct sk_buff **skb, l3_protocol l3_proto, bool syn, bool rst, bool fin)
{
	struct tcphdr *hdr_tcp;
	struct tuple tuple;
	int error;

	switch (l3_proto) {
	case L3PROTO_IPV4:
		error = init_ipv4_tuple(&tuple, "8.7.6.5", 8765, "5.6.7.8", 5678, L4PROTO_TCP);
		if (error)
			return error;
		error = create_skb4_tcp(&tuple, skb, 100, 32);
		if (error)
			return error;
		break;
	case L3PROTO_IPV6:
		error = init_ipv6_tuple(&tuple, "1::2", 1212, "3::4", 3434, L4PROTO_TCP);
		if (error)
			return error;
		error = create_skb6_tcp(&tuple, skb, 100, 32);
		if (error)
			return error;
		break;
	}

	hdr_tcp = tcp_hdr(*skb);
	hdr_tcp->syn = syn;
	hdr_tcp->rst = rst;
	hdr_tcp->fin = fin;

	return 0;
}
Example #3
0
static int init_payload_inner_ipv6(void *target, u16 payload_len)
{
	struct ipv6hdr *hdr_ipv6;
	struct tcphdr *hdr_tcp;
	struct ipv6hdr tmp_hdr_ipv6;
	struct tcphdr tmp_hdr_tcp;
	unsigned char *inner_payload;
	struct tuple tuple6;
	int error;

	if (payload_len <= 0)
		return 0; /* Nothing to do here. */

	error = init_ipv6_tuple(&tuple6, "1::1", 50080, "64::192.0.2.5", 51234, L4PROTO_TCP);
	if (error)
		return error;

	hdr_ipv6 = target;
	hdr_tcp = (struct tcphdr *) (hdr_ipv6 + 1);
	inner_payload = (unsigned char *) (hdr_tcp + 1);

	error = init_ipv6_hdr(&tmp_hdr_ipv6, 1300, NEXTHDR_TCP, &tuple6, true, false, 0, 32);
	if (error)
		return error;

	if (payload_len >= IPV6_HDR_LEN) {
		memcpy(hdr_ipv6, &tmp_hdr_ipv6, IPV6_HDR_LEN);
		payload_len -= IPV6_HDR_LEN;
	} else {
		memcpy(hdr_ipv6, &tmp_hdr_ipv6, payload_len);
		goto end;
	}

	error = init_tcp_hdr(&tmp_hdr_tcp, ETH_P_IPV6, 1300, &tuple6);
	if (error)
		return error;

	if (payload_len >= TCP_HDR_LEN) {
		memcpy(hdr_tcp, &tmp_hdr_tcp, TCP_HDR_LEN);
		payload_len -= TCP_HDR_LEN;
	} else {
		memcpy(hdr_tcp, &tmp_hdr_tcp, payload_len);
		goto end;
	}

	error = init_payload_normal(inner_payload, payload_len);
	if (error)
		return error;

	hdr_tcp->check = csum_ipv6_magic(&hdr_ipv6->saddr, &hdr_ipv6->daddr,
			sizeof(*hdr_tcp) + payload_len, NEXTHDR_TCP,
			csum_partial(hdr_tcp, sizeof(*hdr_tcp) + payload_len, 0));
	/* Fall through. */

end:
	return 0;
}
Example #4
0
static bool divide_skb_test(l4_protocol l4_proto,
		int (*create_skb6_frag_fn)(struct tuple *, struct sk_buff **, u16, u16, bool, bool, u16, u8))
{
	struct sk_buff *skb6 = NULL;
	struct tuple tuple6;
	bool result = true;
	u16 total_payload = 3000;

	/* IPv6 Parameters. (To evaluate). */
	bool is_first[] = {true, false, false};
	bool is_last[] = {false, false, true};
	u16 frag6_offset[] = {0, 1232, 2464};
	u16 *payload6_len, *payload_offset;
	int total_frags6 = 3;

	u16 total_l4_len;
	u16 payload6_udp_icmp_len[] = {1224, 1232, 544};
	u16 payload_udp_icmp_offset[] = {0, 1224, 2456};
	u16 payload6_tcp_len[] = {1212, 1232, 556};
	u16 payload_tcp_offset[] = {0, 1212, 2444};

	if (l4_proto == L4PROTO_TCP) {
		payload6_len = payload6_tcp_len;
		payload_offset = payload_tcp_offset;
		total_l4_len = sizeof(struct tcphdr);
	} else {
		payload6_len = payload6_udp_icmp_len;
		payload_offset = payload_udp_icmp_offset;
		if (l4_proto == L4PROTO_UDP)
			total_l4_len = sizeof(struct udphdr) + total_payload;
		else
			total_l4_len = sizeof(struct icmphdr);
	}

	if (init_ipv6_tuple(&tuple6, "1::1", 6000, "64:ff9b::192.0.2.7", 4000, l4_proto) != 0)
		return false;

	if (create_skb6_frag_fn(&tuple6, &skb6, total_payload, total_l4_len ,false, false, 0, 32) != 0)
		return false;

	/* Just for precaution. */
	skb6->next = NULL;
	skb6->prev = NULL;

	if (divide(skb6, 1280) != 0) {
		kfree_skb_queued(skb6);
		return false;
	}

	result = validate_frags6(skb6, &tuple6, total_frags6, is_first, is_last, frag6_offset,
			payload6_len, payload_offset, total_payload, l4_proto);

	kfree_skb_queued(skb6);
	return result;
}
static bool test_icmp(void)
{
	struct tuple tuple6;
	struct sk_buff *skb;
	bool success = true;

	if (is_error(init_ipv6_tuple(&tuple6,
			CLIENT_ADDR, CLIENT_PORT,
			SERVER_HAIRPIN_ADDR, SERVER_PORT6,
			L4PROTO_ICMP)))
		return false;
	if (is_error(create_skb6_icmp_info(&tuple6, &skb, 100, 32)))
		return false;
	set_sent_skb(NULL);

	success &= assert_equals_int(NF_DROP, core_6to4(skb), "Request result");
	success &= assert_null(get_sent_skb(), "Sent SKB");

	return success;
}
static bool test_determine_in_tuple_ipv6(void)
{
	struct packet pkt;
	struct sk_buff *skb;
	struct tuple actual, expected;
	bool success = true;

	if (is_error(init_ipv6_tuple(&expected, "1::2", 1212, "3::4", 3434, L4PROTO_TCP)))
		return false;
	if (is_error(create_skb6_tcp(&expected, &skb, 8, 32)))
		return false;
	if (is_error(pkt_init_ipv6(&pkt, skb)))
		return false;

	success &= assert_equals_int(VERDICT_CONTINUE, determine_in_tuple(&pkt, &actual), "verdict");
	success &= assert_equals_tuple(&expected, &actual, "tuple");

	kfree_skb(skb);
	return success;
}
Example #7
0
static bool test_6to4(l4_protocol l4_proto)
{
	struct tuple in, out;
	int field = 0;
	bool success = true;

	if (is_error(init_ipv6_tuple(&in, remote6, 1234, local6, 80, l4_proto)))
		return false;

	success &= assert_equals_int(VER_CONTINUE, compute_out_tuple(&in, &out, NULL), "Call");
	success &= assert_equals_int(L3PROTO_IPV4, out.l3_proto, "l3 proto");
 	success &= assert_equals_int(l4_proto, out.l4_proto, "l4 proto");
 	success &= assert_equals_ipv4_str(local4, &out.src.addr4.l3, "src addr");
 	if (l4_proto == L4PROTO_ICMP)
 		success &= assert_equals_u16(80, out.src.addr4.l4, "src port (icmp id)");
 	else
 		success &= assert_equals_u16(5678, out.src.addr4.l4, "src port");
 	success &= assert_equals_ipv4_str(remote4, &out.dst.addr4.l3, "dst addr");
	success &= assert_equals_u16(80, out.dst.addr4.l4, "dst port (icmp id)");
 	success &= assert_equals_int(0, field, "unchanged field");

	return success;
}
Example #8
0
bool validate_inner_pkt_ipv6(unsigned char *payload, u16 len)
{
    struct ipv6hdr *hdr_ipv6;
    struct tcphdr *hdr_tcp;
    unsigned char *inner_payload;
    struct tuple tuple6;

    if (init_ipv6_tuple(&tuple6, "2::2", 4321, "1::1", 1234, L4PROTO_TCP) != 0)
        return false;

    hdr_ipv6 = (struct ipv6hdr *) payload;
    hdr_tcp = (struct tcphdr *) (hdr_ipv6 + 1);
    inner_payload = (unsigned char *) (hdr_tcp + 1);

    if (!validate_ipv6_hdr(hdr_ipv6, 1300, NEXTHDR_TCP, &tuple6))
        return false;
    if (!validate_tcp_hdr(hdr_tcp, &tuple6))
        return false;
    if (!validate_payload(inner_payload, len - sizeof(*hdr_ipv6) - sizeof(*hdr_tcp), 0))
        return false;

    return true;
}
static bool test_determine_in_tuple_ipv6(void)
{
	struct sk_buff *skb;
	struct fragment *frag;
	struct tuple actual, expected;
	struct ipv6_pair pair6;
	bool success = true;

	if (is_error(init_ipv6_tuple(&expected, "1::2", 1212, "3::4", 3434, L4PROTO_TCP)))
		return false;
	if (is_error(init_pair6(&pair6, "1::2", 1212, "3::4", 3434)))
		return false;
	if (is_error(create_skb_ipv6_tcp_fragment_1(&pair6, &skb, 8)))
		return false;
	if (is_error(frag_create_from_skb(skb, &frag)))
		return false;

	success &= assert_equals_int(VER_CONTINUE, determine_in_tuple(frag, &actual), "verdict");
	success &= assert_equals_tuple(&expected, &actual, "tuple");

	frag_kfree(frag);
	return success;
}
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;
}
Example #11
0
static bool test_allocate_ipv4_transport_address(void)
{
	struct tuple client1tuple, client2tuple, client3tuple;
	struct in_addr client1addr4, client2addr4, client3addr4;
	struct tuple *sharing_client_tuple;
	struct in_addr *non_sharing_addr;
	struct ipv4_transport_addr result;
	struct host6_node *host6;
	unsigned int i = 0;
	bool success = true;

	if (is_error(init_ipv6_tuple(&client1tuple, "1::1", 60000, "64:ff9b::1", 60000, L4PROTO_UDP)))
		goto fail;
	if (is_error(init_ipv6_tuple(&client2tuple, "1::2", 60000, "64:ff9b::2", 60000, L4PROTO_UDP)))
		goto fail;
	if (is_error(init_ipv6_tuple(&client3tuple, "1::3", 60000, "64:ff9b::3", 60000, L4PROTO_UDP)))
		goto fail;

	log_debug("IPv6 client 1 arrives and makes 25 connections.");
	/*
	 * Because it's the same IPv6 client, all of those connections should be masked with the same
	 * IPv4 address. This minimizes confusion from remote IPv4 hosts.
	 */

	client1tuple.src.addr6.l4 = 65511;
	if (!test_allocate_aux(&client1tuple, NULL, &client1addr4, true))
		goto fail;

	for (i = 65512; i < 65536; i++) {
		client1tuple.src.addr6.l4 = i;
		if (!test_allocate_aux(&client1tuple, &client1addr4, NULL, true))
			goto fail;
	}

	log_debug("Client 2 arrives and make 50 connections.");
	/*
	 * All of them should share the same IPv4 address,
	 * which should be different from client1's (again, to minimize confusion).
	 */

	client2tuple.src.addr6.l4 = 65486;
	success &= test_allocate_aux(&client2tuple, NULL, &client2addr4, true);
	success &= assert_true(client1addr4.s_addr != client2addr4.s_addr,
			"the nodes are being masked with different addresses");
	if (!success)
		goto fail;

	for (i = 65487; i < 65536; i++) {
		client2tuple.src.addr6.l4 = i;
		if (!test_allocate_aux(&client2tuple, &client2addr4, NULL, true))
			goto fail;
	}

	log_debug("Client 1 makes another 25 connections.");
	/*
	 * Because there are still ports available, he should still get the same IPv4 address.
	 * Essentially, this proves that client2's intervention doesn't affect client 1's connections.
	 */

	for (i = 65486; i < 65511; i++) {
		client1tuple.src.addr6.l4 = i;
		if (!test_allocate_aux(&client1tuple, &client1addr4, NULL, true))
			goto fail;
	}

	log_debug("Client 3 arrives and hogs up all of its address's low ports.");
	/*
	 * At this point, both IPv4 addresses have 50 high ports taken.
	 * Because both IPv4 addresses are taken, client 3 will share its IPv4 address with someone.
	 */
	client3tuple.src.addr6.l4 = 0;
	if (!test_allocate_aux(&client3tuple, NULL, &client3addr4, true))
		goto fail;

	for (i = 1; i < 1024; i++) {
		client3tuple.src.addr6.l4 = i;
		if (!test_allocate_aux(&client3tuple, &client3addr4, NULL, true))
			goto fail;
	}

	log_debug("The client that shares an address with client 3 requests a low port.");
	/*
	 * Because all of them are taken, he gets the same address but a runner-up high port instead.
	 */

	if (addr4_equals(&client1addr4, &client3addr4)) {
		sharing_client_tuple = &client1tuple;
		non_sharing_addr = &client2addr4;
	} else if (addr4_equals(&client2addr4, &client3addr4)) {
		sharing_client_tuple = &client2tuple;
		non_sharing_addr = &client1addr4;
	} else {
		log_err("Client 3 doesn't share its IPv4 address with anyone, despite validations.");
		goto fail;
	}


	if (is_error(host6_node_get_or_create(&sharing_client_tuple->src.addr6.l3, &host6)))
		goto fail;

	sharing_client_tuple->src.addr6.l4 = 0;
	success &= assert_equals_int(0, allocate_transport_address(host6, sharing_client_tuple,
			&result), "result 3");
	success &= assert_equals_ipv4(&client3addr4, &result.l3, "runnerup still gets his addr");
	success &= assert_true(is_high(result.l4), "runnerup gets a high port");
	success &= bib_inject(&sharing_client_tuple->src.addr6.l3, sharing_client_tuple->src.addr6.l4,
			&result.l3, result.l4, L4PROTO_UDP) != NULL;

	host6_node_return(host6);
	if (!success)
		goto fail;

	log_debug("Client 3 now hogs up all of its address's remaining ports.");
	/* 51 high ports were already taken, so this will stop early. */
	for (i = 1024; i < 65485; i++) {
		client3tuple.src.addr6.l4 = i;
		if (!test_allocate_aux(&client3tuple, &client3addr4, NULL, i != 65484))
			goto fail;
	}

	/*
	 * At this point, client's address has 50 + 1024 + 1 + 64461 = 65536 ports taken.
	 * ie. It no longer has any ports.
	 */

	log_debug("Then, the function will fall back to use the other address.");
	client3tuple.src.addr6.l4 = i;
	if (is_error(host6_node_get_or_create(&client3tuple.src.addr6.l3, &host6)))
		goto fail;

	success &= assert_equals_int(0, allocate_transport_address(host6, &client3tuple, &result),
			"function result");
	success &= assert_true(client3addr4.s_addr != result.l3.s_addr,
			"node gets a runnerup address");
	success &= bib_inject(&client3tuple.src.addr6.l3, client3tuple.src.addr6.l4,
			&result.l3, result.l4, L4PROTO_UDP) != NULL;

	host6_node_return(host6);
	if (!success)
		goto fail;

	log_debug("It will also fall back to use the other address as the other sharing node now hogs "
			"all remaining ports.");
	/*
	 * 51 high ports ports were already taken, so this will stop early.
	 * Also, the sharing client already requested port 0, so we have to start at 1.
	 */
	for (i = 1; i < 65486; i++) {
		sharing_client_tuple->src.addr6.l4 = i;
		if (!test_allocate_aux(sharing_client_tuple, non_sharing_addr, NULL,  i != 65485))
			goto fail;
	}


	log_debug("Now the pool is completely exhausted, so further requests cannot fall back.");

	if (is_error(host6_node_get_or_create(&client1tuple.src.addr6.l3, &host6)))
		goto fail;
	success &= assert_equals_int(-ESRCH, allocate_transport_address(host6, &client1tuple,
			&result), "client 1's request is denied");
	host6_node_return(host6);

	if (is_error(host6_node_get_or_create(&client2tuple.src.addr6.l3, &host6)))
		goto fail;
	success &= assert_equals_int(-ESRCH, allocate_transport_address(host6, &client2tuple,
			&result), "client 2's request is denied");
	host6_node_return(host6);

	if (is_error(host6_node_get_or_create(&client3tuple.src.addr6.l3, &host6)))
		goto fail;
	success &= assert_equals_int(-ESRCH, allocate_transport_address(host6, &client3tuple,
			&result), "client 3's request is denied");
	host6_node_return(host6);

	return success;

fail:
	log_debug("i was %u.", i);
	return false;
}