static bool test_icmp(void) { struct xlation state; struct sk_buff *skb; bool success = true; xlation_init(&state, &jool); log_debug("== IPv4 packet attempts to be translated without state =="); if (create_skb4_icmp_info("0.0.0.4", "192.0.2.128", 1024, 16, 32, &skb)) return false; if (pkt_init_ipv4(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(UNTRANSLATABLE, ipv4_simple(&state), "result 1"); success &= assert_bib_count(0, L4PROTO_ICMP); success &= assert_session_count(0, L4PROTO_ICMP); kfree_skb(skb); log_debug("== IPv6 packet and gets translated correctly =="); if (create_skb6_icmp_info("1::2", "3::4", 1212, 16, 32, &skb)) return false; if (pkt_init_ipv6(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(CONTINUE, ipv6_simple(&state), "result 2"); success &= assert_bib_count(1, L4PROTO_ICMP); success &= assert_bib_exists("1::2", 1212, "192.0.2.128", 1024, L4PROTO_ICMP, 1); success &= assert_session_count(1, L4PROTO_ICMP); success &= assert_session_exists("1::2", 1212, "3::4", 1212, "192.0.2.128", 1024, "0.0.0.4", 1024, L4PROTO_ICMP, ESTABLISHED, SESSION_TIMER_EST, ICMP_DEFAULT); kfree_skb(skb); log_debug("== Now that there's state, the IPv4 packet manages to traverse =="); if (!invert_packet(&state, &skb)) return false; success &= ASSERT_VERDICT(CONTINUE, ipv4_simple(&state), "result 3"); success &= assert_bib_count(1, L4PROTO_ICMP); success &= assert_bib_exists("1::2", 1212, "192.0.2.128", 1024, L4PROTO_ICMP, 1); success &= assert_session_count(1, L4PROTO_ICMP); success &= assert_session_exists("1::2", 1212, "3::4", 1212, "192.0.2.128", 1024, "0.0.0.4", 1024, L4PROTO_ICMP, ESTABLISHED, SESSION_TIMER_EST, ICMP_DEFAULT); kfree_skb(skb); return success; }
static unsigned int nat64_core(struct sk_buff *skb_in, bool (*compute_out_tuple_fn)(struct tuple *, struct sk_buff *, struct tuple *), bool (*translate_packet_fn)(struct tuple *, struct sk_buff *, struct sk_buff **), bool (*send_packet_fn)(struct sk_buff *, struct sk_buff *)) { struct sk_buff *skb_out = NULL; struct tuple tuple_in, tuple_out; if (!determine_in_tuple(skb_in, &tuple_in)) goto free_and_fail; if (filtering_and_updating(skb_in, &tuple_in) != NF_ACCEPT) goto free_and_fail; if (!compute_out_tuple_fn(&tuple_in, skb_in, &tuple_out)) goto free_and_fail; if (!translate_packet_fn(&tuple_out, skb_in, &skb_out)) goto free_and_fail; if (is_hairpin(&tuple_out)) { if (!handling_hairpinning(skb_out, &tuple_out)) goto free_and_fail; } else { if (!send_packet_fn(skb_in, skb_out)) goto fail; } log_debug("Success."); return NF_DROP; /* Lol, the irony. */ free_and_fail: kfree_skb(skb_out); /* Fall through. */ fail: log_debug("Failure."); return NF_DROP; }
static unsigned int core_common(struct packet *in) { struct packet out; struct tuple tuple_in; struct tuple tuple_out; verdict result; result = determine_in_tuple(in, &tuple_in); if (result != VERDICT_CONTINUE) goto end; result = filtering_and_updating(in, &tuple_in); if (result != VERDICT_CONTINUE) goto end; result = compute_out_tuple(&tuple_in, &tuple_out, in); if (result != VERDICT_CONTINUE) goto end; result = translating_the_packet(&tuple_out, in, &out); if (result != VERDICT_CONTINUE) goto end; if (is_hairpin(&out)) { result = handling_hairpinning(&out, &tuple_out); kfree_skb(out.skb); } else { result = sendpkt_send(in, &out); /* send_pkt releases skb_out regardless of verdict. */ } if (result != VERDICT_CONTINUE) goto end; log_debug("Success."); /* * The new packet was sent, so the original one can die; drop it. * * NF_DROP translates into an error (see nf_hook_slow()). * Sending a replacing & translated version of the packet should not count as an error, * so we free the incoming packet ourselves and return NF_STOLEN on success. */ kfree_skb(in->skb); result = VERDICT_STOLEN; /* Fall through. */ end: if (result == VERDICT_ACCEPT) log_debug("Returning the packet to the kernel."); return (unsigned int) result; }
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; }
static bool test_determine_in_tuple_ipv4(void) { struct packet pkt; struct sk_buff *skb; struct tuple actual, expected; bool success = true; if (is_error(init_ipv4_tuple(&expected, "8.7.6.5", 8765, "5.6.7.8", 5678, L4PROTO_UDP))) return false; if (is_error(create_skb4_udp(&expected, &skb, 8, 32))) return false; if (is_error(pkt_init_ipv4(&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; }
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_determine_in_tuple_ipv4(void) { struct sk_buff *skb; struct fragment *frag; struct tuple actual, expected; struct ipv4_pair pair4; bool success = true; if (is_error(init_ipv4_tuple(&expected, "8.7.6.5", 8765, "5.6.7.8", 5678, L4PROTO_UDP))) return false; if (is_error(init_pair4(&pair4, "8.7.6.5", 8765, "5.6.7.8", 5678))) return false; if (is_error(create_skb_ipv4_udp(&pair4, &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_filtering_and_updating(void) { struct xlation state; struct sk_buff *skb; bool success = true; xlation_init(&state, &jool); log_debug("== ICMPv4 errors should succeed but not affect the tables =="); if (create_skb4_icmp_error("8.7.6.5", "192.0.2.128", 100, 32, &skb)) return false; if (pkt_init_ipv4(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(CONTINUE, filtering_and_updating(&state), "ICMP error 1"); success &= assert_bib_count(0, L4PROTO_TCP); success &= assert_bib_count(0, L4PROTO_UDP); success &= assert_bib_count(0, L4PROTO_ICMP); success &= assert_session_count(0, L4PROTO_TCP); success &= assert_session_count(0, L4PROTO_UDP); success &= assert_session_count(0, L4PROTO_ICMP); kfree_skb(skb); if (!success) return false; log_debug("== ICMPv6 errors should succeed but not affect the tables =="); if (create_skb6_icmp_error("1::2", "3::3:4", 100, 32, &skb)) return false; if (pkt_init_ipv6(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(CONTINUE, filtering_and_updating(&state), "ICMP error 2"); success &= assert_bib_count(0, L4PROTO_TCP); success &= assert_bib_count(0, L4PROTO_UDP); success &= assert_bib_count(0, L4PROTO_ICMP); success &= assert_session_count(0, L4PROTO_TCP); success &= assert_session_count(0, L4PROTO_UDP); success &= assert_session_count(0, L4PROTO_ICMP); kfree_skb(skb); if (!success) return false; log_debug("== Hairpinning loops should be dropped =="); if (create_skb6_udp("3::1:2", 1212, "3::3:4", 3434, 100, 32, &skb)) return false; if (pkt_init_ipv6(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(DROP, filtering_and_updating(&state), "Hairpinning"); success &= assert_bib_count(0, L4PROTO_UDP); success &= assert_session_count(0, L4PROTO_UDP); kfree_skb(skb); if (!success) return false; log_debug("== Packets not headed to pool6 must not be translated =="); if (create_skb6_udp("1::2", 1212, "4::1", 3434, 100, 32, &skb)) return false; if (pkt_init_ipv6(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(UNTRANSLATABLE, filtering_and_updating(&state), "Not pool6 packet"); success &= assert_bib_count(0, L4PROTO_UDP); success &= assert_session_count(0, L4PROTO_UDP); kfree_skb(skb); if (!success) return false; log_debug("== Packets not headed to pool4 must not be translated =="); if (create_skb4_udp("8.7.6.5", 8765, "5.6.7.8", 5678, 100, 32, &skb)) return false; if (pkt_init_ipv4(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(UNTRANSLATABLE, filtering_and_updating(&state), "Not pool4 packet"); success &= assert_bib_count(0, L4PROTO_UDP); success &= assert_session_count(0, L4PROTO_UDP); kfree_skb(skb); if (!success) return false; log_debug("== Other IPv6 packets should survive validations =="); if (create_skb6_udp("1::2", 1212, "3::3:4", 3434, 100, 32, &skb)) return false; if (pkt_init_ipv6(&state, skb)) return false; if (determine_in_tuple(&state) != VERDICT_CONTINUE) return false; success &= ASSERT_VERDICT(CONTINUE, filtering_and_updating(&state), "IPv6 success"); success &= assert_bib_count(1, L4PROTO_UDP); success &= assert_session_count(1, L4PROTO_UDP); kfree_skb(skb); if (!success) return false; log_debug("== Other IPv4 packets should survive validations =="); if (!invert_packet(&state, &skb)) return false; success &= ASSERT_VERDICT(CONTINUE, filtering_and_updating(&state), "IPv4 success"); success &= assert_bib_count(1, L4PROTO_UDP); success &= assert_session_count(1, L4PROTO_UDP); kfree_skb(skb); return success; }