Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | // SPDX-License-Identifier: GPL-2.0 #include <test_progs.h> #include <network_helpers.h> #include <linux/netfilter/nf_conntrack_common.h> #include "test_bpf_nf.skel.h" #include "test_bpf_nf_fail.skel.h" static char log_buf[1024 * 1024]; struct { const char *prog_name; const char *err_msg; } test_bpf_nf_fail_tests[] = { { "alloc_release", "kernel function bpf_ct_release args#0 expected pointer to STRUCT nf_conn but" }, { "insert_insert", "kernel function bpf_ct_insert_entry args#0 expected pointer to STRUCT nf_conn___init but" }, { "lookup_insert", "kernel function bpf_ct_insert_entry args#0 expected pointer to STRUCT nf_conn___init but" }, { "set_timeout_after_insert", "kernel function bpf_ct_set_timeout args#0 expected pointer to STRUCT nf_conn___init but" }, { "set_status_after_insert", "kernel function bpf_ct_set_status args#0 expected pointer to STRUCT nf_conn___init but" }, { "change_timeout_after_alloc", "kernel function bpf_ct_change_timeout args#0 expected pointer to STRUCT nf_conn but" }, { "change_status_after_alloc", "kernel function bpf_ct_change_status args#0 expected pointer to STRUCT nf_conn but" }, { "write_not_allowlisted_field", "no write support to nf_conn at off" }, }; enum { TEST_XDP, TEST_TC_BPF, }; #define TIMEOUT_MS 3000 #define IPS_STATUS_MASK (IPS_CONFIRMED | IPS_SEEN_REPLY | \ IPS_SRC_NAT_DONE | IPS_DST_NAT_DONE | \ IPS_SRC_NAT | IPS_DST_NAT) static int connect_to_server(int srv_fd) { int fd = -1; fd = socket(AF_INET, SOCK_STREAM, 0); if (!ASSERT_GE(fd, 0, "socket")) goto out; if (!ASSERT_EQ(connect_fd_to_fd(fd, srv_fd, TIMEOUT_MS), 0, "connect_fd_to_fd")) { close(fd); fd = -1; } out: return fd; } static void test_bpf_nf_ct(int mode) { const char *iptables = "iptables -t raw %s PREROUTING -j CONNMARK --set-mark 42/0"; int srv_fd = -1, client_fd = -1, srv_client_fd = -1; struct sockaddr_in peer_addr = {}; struct test_bpf_nf *skel; int prog_fd, err; socklen_t len; u16 srv_port; char cmd[64]; LIBBPF_OPTS(bpf_test_run_opts, topts, .data_in = &pkt_v4, .data_size_in = sizeof(pkt_v4), .repeat = 1, ); skel = test_bpf_nf__open_and_load(); if (!ASSERT_OK_PTR(skel, "test_bpf_nf__open_and_load")) return; /* Enable connection tracking */ snprintf(cmd, sizeof(cmd), iptables, "-A"); if (!ASSERT_OK(system(cmd), "iptables")) goto end; srv_port = (mode == TEST_XDP) ? 5005 : 5006; srv_fd = start_server(AF_INET, SOCK_STREAM, "127.0.0.1", srv_port, TIMEOUT_MS); if (!ASSERT_GE(srv_fd, 0, "start_server")) goto end; client_fd = connect_to_server(srv_fd); if (!ASSERT_GE(client_fd, 0, "connect_to_server")) goto end; len = sizeof(peer_addr); srv_client_fd = accept(srv_fd, (struct sockaddr *)&peer_addr, &len); if (!ASSERT_GE(srv_client_fd, 0, "accept")) goto end; if (!ASSERT_EQ(len, sizeof(struct sockaddr_in), "sockaddr len")) goto end; skel->bss->saddr = peer_addr.sin_addr.s_addr; skel->bss->sport = peer_addr.sin_port; skel->bss->daddr = peer_addr.sin_addr.s_addr; skel->bss->dport = htons(srv_port); if (mode == TEST_XDP) prog_fd = bpf_program__fd(skel->progs.nf_xdp_ct_test); else prog_fd = bpf_program__fd(skel->progs.nf_skb_ct_test); err = bpf_prog_test_run_opts(prog_fd, &topts); if (!ASSERT_OK(err, "bpf_prog_test_run")) goto end; ASSERT_EQ(skel->bss->test_einval_bpf_tuple, -EINVAL, "Test EINVAL for NULL bpf_tuple"); ASSERT_EQ(skel->bss->test_einval_reserved, -EINVAL, "Test EINVAL for reserved not set to 0"); ASSERT_EQ(skel->bss->test_einval_netns_id, -EINVAL, "Test EINVAL for netns_id < -1"); ASSERT_EQ(skel->bss->test_einval_len_opts, -EINVAL, "Test EINVAL for len__opts != NF_BPF_CT_OPTS_SZ"); ASSERT_EQ(skel->bss->test_eproto_l4proto, -EPROTO, "Test EPROTO for l4proto != TCP or UDP"); ASSERT_EQ(skel->bss->test_enonet_netns_id, -ENONET, "Test ENONET for bad but valid netns_id"); ASSERT_EQ(skel->bss->test_enoent_lookup, -ENOENT, "Test ENOENT for failed lookup"); ASSERT_EQ(skel->bss->test_eafnosupport, -EAFNOSUPPORT, "Test EAFNOSUPPORT for invalid len__tuple"); ASSERT_EQ(skel->data->test_alloc_entry, 0, "Test for alloc new entry"); ASSERT_EQ(skel->data->test_insert_entry, 0, "Test for insert new entry"); ASSERT_EQ(skel->data->test_succ_lookup, 0, "Test for successful lookup"); /* allow some tolerance for test_delta_timeout value to avoid races. */ ASSERT_GT(skel->bss->test_delta_timeout, 8, "Test for min ct timeout update"); ASSERT_LE(skel->bss->test_delta_timeout, 10, "Test for max ct timeout update"); ASSERT_EQ(skel->bss->test_insert_lookup_mark, 77, "Test for insert and lookup mark value"); ASSERT_EQ(skel->bss->test_status, IPS_STATUS_MASK, "Test for ct status update "); ASSERT_EQ(skel->data->test_exist_lookup, 0, "Test existing connection lookup"); ASSERT_EQ(skel->bss->test_exist_lookup_mark, 43, "Test existing connection lookup ctmark"); ASSERT_EQ(skel->data->test_snat_addr, 0, "Test for source natting"); ASSERT_EQ(skel->data->test_dnat_addr, 0, "Test for destination natting"); end: if (client_fd != -1) close(client_fd); if (srv_client_fd != -1) close(srv_client_fd); if (srv_fd != -1) close(srv_fd); snprintf(cmd, sizeof(cmd), iptables, "-D"); system(cmd); test_bpf_nf__destroy(skel); } static void test_bpf_nf_ct_fail(const char *prog_name, const char *err_msg) { LIBBPF_OPTS(bpf_object_open_opts, opts, .kernel_log_buf = log_buf, .kernel_log_size = sizeof(log_buf), .kernel_log_level = 1); struct test_bpf_nf_fail *skel; struct bpf_program *prog; int ret; skel = test_bpf_nf_fail__open_opts(&opts); if (!ASSERT_OK_PTR(skel, "test_bpf_nf_fail__open")) return; prog = bpf_object__find_program_by_name(skel->obj, prog_name); if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) goto end; bpf_program__set_autoload(prog, true); ret = test_bpf_nf_fail__load(skel); if (!ASSERT_ERR(ret, "test_bpf_nf_fail__load must fail")) goto end; if (!ASSERT_OK_PTR(strstr(log_buf, err_msg), "expected error message")) { fprintf(stderr, "Expected: %s\n", err_msg); fprintf(stderr, "Verifier: %s\n", log_buf); } end: test_bpf_nf_fail__destroy(skel); } void test_bpf_nf(void) { int i; if (test__start_subtest("xdp-ct")) test_bpf_nf_ct(TEST_XDP); if (test__start_subtest("tc-bpf-ct")) test_bpf_nf_ct(TEST_TC_BPF); for (i = 0; i < ARRAY_SIZE(test_bpf_nf_fail_tests); i++) { if (test__start_subtest(test_bpf_nf_fail_tests[i].prog_name)) test_bpf_nf_ct_fail(test_bpf_nf_fail_tests[i].prog_name, test_bpf_nf_fail_tests[i].err_msg); } } |