Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: netfilter: add nfqueue test case

Add a test case to check nf queue infrastructure.
Could be extended in the future to also cover serialization of
conntrack, uid and secctx attributes in nfqueue.

For now, this checks that 'queue bypass' works, that a queue rule with
no bypass option blocks traffic and that userspace receives the expected
number of packets.
For this we add two queues and hook all of
prerouting/input/forward/output/postrouting.

Packets get queued twice with a dummy base chain in between:
This passes with current nf tree, but reverting
commit 946c0d8e6ed4 ("netfilter: nf_queue: fix reinject verdict handling")
makes this trip (it processes 30 instead of expected 20 packets).

v2: update config file with queue and other options missing/needed for
other tests.
v3: also test with tcp, this reveals problem with commit
28f8bfd1ac94 ("netfilter: Support iif matches in POSTROUTING"), due to
skb->dev pointing at another skb in the retransmit rbtree (skb->dev
aliases to rbnode child).

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
a64d558d bcfabee1

+695 -1
+5 -1
tools/testing/selftests/netfilter/Makefile
··· 3 3 4 4 TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \ 5 5 conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \ 6 - nft_concat_range.sh 6 + nft_concat_range.sh \ 7 + nft_queue.sh 8 + 9 + LDLIBS = -lmnl 10 + TEST_GEN_FILES = nf-queue 7 11 8 12 include ../lib.mk
+6
tools/testing/selftests/netfilter/config
··· 1 1 CONFIG_NET_NS=y 2 2 CONFIG_NF_TABLES_INET=y 3 + CONFIG_NFT_QUEUE=m 4 + CONFIG_NFT_NAT=m 5 + CONFIG_NFT_REDIR=m 6 + CONFIG_NFT_MASQ=m 7 + CONFIG_NFT_FLOW_OFFLOAD=m 8 + CONFIG_NF_CT_NETLINK=m
+352
tools/testing/selftests/netfilter/nf-queue.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <errno.h> 4 + #include <stdbool.h> 5 + #include <stdio.h> 6 + #include <stdint.h> 7 + #include <stdlib.h> 8 + #include <unistd.h> 9 + #include <string.h> 10 + #include <time.h> 11 + #include <arpa/inet.h> 12 + 13 + #include <libmnl/libmnl.h> 14 + #include <linux/netfilter.h> 15 + #include <linux/netfilter/nfnetlink.h> 16 + #include <linux/netfilter/nfnetlink_queue.h> 17 + 18 + struct options { 19 + bool count_packets; 20 + int verbose; 21 + unsigned int queue_num; 22 + unsigned int timeout; 23 + }; 24 + 25 + static unsigned int queue_stats[5]; 26 + static struct options opts; 27 + 28 + static void help(const char *p) 29 + { 30 + printf("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num]\n", p); 31 + } 32 + 33 + static int parse_attr_cb(const struct nlattr *attr, void *data) 34 + { 35 + const struct nlattr **tb = data; 36 + int type = mnl_attr_get_type(attr); 37 + 38 + /* skip unsupported attribute in user-space */ 39 + if (mnl_attr_type_valid(attr, NFQA_MAX) < 0) 40 + return MNL_CB_OK; 41 + 42 + switch (type) { 43 + case NFQA_MARK: 44 + case NFQA_IFINDEX_INDEV: 45 + case NFQA_IFINDEX_OUTDEV: 46 + case NFQA_IFINDEX_PHYSINDEV: 47 + case NFQA_IFINDEX_PHYSOUTDEV: 48 + if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) { 49 + perror("mnl_attr_validate"); 50 + return MNL_CB_ERROR; 51 + } 52 + break; 53 + case NFQA_TIMESTAMP: 54 + if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, 55 + sizeof(struct nfqnl_msg_packet_timestamp)) < 0) { 56 + perror("mnl_attr_validate2"); 57 + return MNL_CB_ERROR; 58 + } 59 + break; 60 + case NFQA_HWADDR: 61 + if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, 62 + sizeof(struct nfqnl_msg_packet_hw)) < 0) { 63 + perror("mnl_attr_validate2"); 64 + return MNL_CB_ERROR; 65 + } 66 + break; 67 + case NFQA_PAYLOAD: 68 + break; 69 + } 70 + tb[type] = attr; 71 + return MNL_CB_OK; 72 + } 73 + 74 + static int queue_cb(const struct nlmsghdr *nlh, void *data) 75 + { 76 + struct nlattr *tb[NFQA_MAX+1] = { 0 }; 77 + struct nfqnl_msg_packet_hdr *ph = NULL; 78 + uint32_t id = 0; 79 + 80 + (void)data; 81 + 82 + mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb); 83 + if (tb[NFQA_PACKET_HDR]) { 84 + ph = mnl_attr_get_payload(tb[NFQA_PACKET_HDR]); 85 + id = ntohl(ph->packet_id); 86 + 87 + if (opts.verbose > 0) 88 + printf("packet hook=%u, hwproto 0x%x", 89 + ntohs(ph->hw_protocol), ph->hook); 90 + 91 + if (ph->hook >= 5) { 92 + fprintf(stderr, "Unknown hook %d\n", ph->hook); 93 + return MNL_CB_ERROR; 94 + } 95 + 96 + if (opts.verbose > 0) { 97 + uint32_t skbinfo = 0; 98 + 99 + if (tb[NFQA_SKB_INFO]) 100 + skbinfo = ntohl(mnl_attr_get_u32(tb[NFQA_SKB_INFO])); 101 + if (skbinfo & NFQA_SKB_CSUMNOTREADY) 102 + printf(" csumnotready"); 103 + if (skbinfo & NFQA_SKB_GSO) 104 + printf(" gso"); 105 + if (skbinfo & NFQA_SKB_CSUM_NOTVERIFIED) 106 + printf(" csumnotverified"); 107 + puts(""); 108 + } 109 + 110 + if (opts.count_packets) 111 + queue_stats[ph->hook]++; 112 + } 113 + 114 + return MNL_CB_OK + id; 115 + } 116 + 117 + static struct nlmsghdr * 118 + nfq_build_cfg_request(char *buf, uint8_t command, int queue_num) 119 + { 120 + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); 121 + struct nfqnl_msg_config_cmd cmd = { 122 + .command = command, 123 + .pf = htons(AF_INET), 124 + }; 125 + struct nfgenmsg *nfg; 126 + 127 + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG; 128 + nlh->nlmsg_flags = NLM_F_REQUEST; 129 + 130 + nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); 131 + 132 + nfg->nfgen_family = AF_UNSPEC; 133 + nfg->version = NFNETLINK_V0; 134 + nfg->res_id = htons(queue_num); 135 + 136 + mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd); 137 + 138 + return nlh; 139 + } 140 + 141 + static struct nlmsghdr * 142 + nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num) 143 + { 144 + struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); 145 + struct nfqnl_msg_config_params params = { 146 + .copy_range = htonl(range), 147 + .copy_mode = mode, 148 + }; 149 + struct nfgenmsg *nfg; 150 + 151 + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG; 152 + nlh->nlmsg_flags = NLM_F_REQUEST; 153 + 154 + nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); 155 + nfg->nfgen_family = AF_UNSPEC; 156 + nfg->version = NFNETLINK_V0; 157 + nfg->res_id = htons(queue_num); 158 + 159 + mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), &params); 160 + 161 + return nlh; 162 + } 163 + 164 + static struct nlmsghdr * 165 + nfq_build_verdict(char *buf, int id, int queue_num, int verd) 166 + { 167 + struct nfqnl_msg_verdict_hdr vh = { 168 + .verdict = htonl(verd), 169 + .id = htonl(id), 170 + }; 171 + struct nlmsghdr *nlh; 172 + struct nfgenmsg *nfg; 173 + 174 + nlh = mnl_nlmsg_put_header(buf); 175 + nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT; 176 + nlh->nlmsg_flags = NLM_F_REQUEST; 177 + nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); 178 + nfg->nfgen_family = AF_UNSPEC; 179 + nfg->version = NFNETLINK_V0; 180 + nfg->res_id = htons(queue_num); 181 + 182 + mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh); 183 + 184 + return nlh; 185 + } 186 + 187 + static void print_stats(void) 188 + { 189 + unsigned int last, total; 190 + int i; 191 + 192 + if (!opts.count_packets) 193 + return; 194 + 195 + total = 0; 196 + last = queue_stats[0]; 197 + 198 + for (i = 0; i < 5; i++) { 199 + printf("hook %d packets %08u\n", i, queue_stats[i]); 200 + last = queue_stats[i]; 201 + total += last; 202 + } 203 + 204 + printf("%u packets total\n", total); 205 + } 206 + 207 + struct mnl_socket *open_queue(void) 208 + { 209 + char buf[MNL_SOCKET_BUFFER_SIZE]; 210 + unsigned int queue_num; 211 + struct mnl_socket *nl; 212 + struct nlmsghdr *nlh; 213 + struct timeval tv; 214 + uint32_t flags; 215 + 216 + nl = mnl_socket_open(NETLINK_NETFILTER); 217 + if (nl == NULL) { 218 + perror("mnl_socket_open"); 219 + exit(EXIT_FAILURE); 220 + } 221 + 222 + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { 223 + perror("mnl_socket_bind"); 224 + exit(EXIT_FAILURE); 225 + } 226 + 227 + queue_num = opts.queue_num; 228 + nlh = nfq_build_cfg_request(buf, NFQNL_CFG_CMD_BIND, queue_num); 229 + 230 + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 231 + perror("mnl_socket_sendto"); 232 + exit(EXIT_FAILURE); 233 + } 234 + 235 + nlh = nfq_build_cfg_params(buf, NFQNL_COPY_PACKET, 0xFFFF, queue_num); 236 + 237 + flags = NFQA_CFG_F_GSO | NFQA_CFG_F_UID_GID; 238 + mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(flags)); 239 + mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(flags)); 240 + 241 + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 242 + perror("mnl_socket_sendto"); 243 + exit(EXIT_FAILURE); 244 + } 245 + 246 + memset(&tv, 0, sizeof(tv)); 247 + tv.tv_sec = opts.timeout; 248 + if (opts.timeout && setsockopt(mnl_socket_get_fd(nl), 249 + SOL_SOCKET, SO_RCVTIMEO, 250 + &tv, sizeof(tv))) { 251 + perror("setsockopt(SO_RCVTIMEO)"); 252 + exit(EXIT_FAILURE); 253 + } 254 + 255 + return nl; 256 + } 257 + 258 + static int mainloop(void) 259 + { 260 + unsigned int buflen = 64 * 1024 + MNL_SOCKET_BUFFER_SIZE; 261 + struct mnl_socket *nl; 262 + struct nlmsghdr *nlh; 263 + unsigned int portid; 264 + char *buf; 265 + int ret; 266 + 267 + buf = malloc(buflen); 268 + if (!buf) { 269 + perror("malloc"); 270 + exit(EXIT_FAILURE); 271 + } 272 + 273 + nl = open_queue(); 274 + portid = mnl_socket_get_portid(nl); 275 + 276 + for (;;) { 277 + uint32_t id; 278 + 279 + ret = mnl_socket_recvfrom(nl, buf, buflen); 280 + if (ret == -1) { 281 + if (errno == ENOBUFS) 282 + continue; 283 + 284 + if (errno == EAGAIN) { 285 + errno = 0; 286 + ret = 0; 287 + break; 288 + } 289 + 290 + perror("mnl_socket_recvfrom"); 291 + exit(EXIT_FAILURE); 292 + } 293 + 294 + ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL); 295 + if (ret < 0) { 296 + perror("mnl_cb_run"); 297 + exit(EXIT_FAILURE); 298 + } 299 + 300 + id = ret - MNL_CB_OK; 301 + nlh = nfq_build_verdict(buf, id, opts.queue_num, NF_ACCEPT); 302 + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { 303 + perror("mnl_socket_sendto"); 304 + exit(EXIT_FAILURE); 305 + } 306 + } 307 + 308 + mnl_socket_close(nl); 309 + 310 + return ret; 311 + } 312 + 313 + static void parse_opts(int argc, char **argv) 314 + { 315 + int c; 316 + 317 + while ((c = getopt(argc, argv, "chvt:q:")) != -1) { 318 + switch (c) { 319 + case 'c': 320 + opts.count_packets = true; 321 + break; 322 + case 'h': 323 + help(argv[0]); 324 + exit(0); 325 + break; 326 + case 'q': 327 + opts.queue_num = atoi(optarg); 328 + if (opts.queue_num > 0xffff) 329 + opts.queue_num = 0; 330 + break; 331 + case 't': 332 + opts.timeout = atoi(optarg); 333 + break; 334 + case 'v': 335 + opts.verbose++; 336 + break; 337 + } 338 + } 339 + } 340 + 341 + int main(int argc, char *argv[]) 342 + { 343 + int ret; 344 + 345 + parse_opts(argc, argv); 346 + 347 + ret = mainloop(); 348 + if (opts.count_packets) 349 + print_stats(); 350 + 351 + return ret; 352 + }
+332
tools/testing/selftests/netfilter/nft_queue.sh
··· 1 + #!/bin/bash 2 + # 3 + # This tests nf_queue: 4 + # 1. can process packets from all hooks 5 + # 2. support running nfqueue from more than one base chain 6 + # 7 + # Kselftest framework requirement - SKIP code is 4. 8 + ksft_skip=4 9 + ret=0 10 + 11 + sfx=$(mktemp -u "XXXXXXXX") 12 + ns1="ns1-$sfx" 13 + ns2="ns2-$sfx" 14 + nsrouter="nsrouter-$sfx" 15 + 16 + cleanup() 17 + { 18 + ip netns del ${ns1} 19 + ip netns del ${ns2} 20 + ip netns del ${nsrouter} 21 + rm -f "$TMPFILE0" 22 + rm -f "$TMPFILE1" 23 + } 24 + 25 + nft --version > /dev/null 2>&1 26 + if [ $? -ne 0 ];then 27 + echo "SKIP: Could not run test without nft tool" 28 + exit $ksft_skip 29 + fi 30 + 31 + ip -Version > /dev/null 2>&1 32 + if [ $? -ne 0 ];then 33 + echo "SKIP: Could not run test without ip tool" 34 + exit $ksft_skip 35 + fi 36 + 37 + ip netns add ${nsrouter} 38 + if [ $? -ne 0 ];then 39 + echo "SKIP: Could not create net namespace" 40 + exit $ksft_skip 41 + fi 42 + 43 + TMPFILE0=$(mktemp) 44 + TMPFILE1=$(mktemp) 45 + trap cleanup EXIT 46 + 47 + ip netns add ${ns1} 48 + ip netns add ${ns2} 49 + 50 + ip link add veth0 netns ${nsrouter} type veth peer name eth0 netns ${ns1} > /dev/null 2>&1 51 + if [ $? -ne 0 ];then 52 + echo "SKIP: No virtual ethernet pair device support in kernel" 53 + exit $ksft_skip 54 + fi 55 + ip link add veth1 netns ${nsrouter} type veth peer name eth0 netns ${ns2} 56 + 57 + ip -net ${nsrouter} link set lo up 58 + ip -net ${nsrouter} link set veth0 up 59 + ip -net ${nsrouter} addr add 10.0.1.1/24 dev veth0 60 + ip -net ${nsrouter} addr add dead:1::1/64 dev veth0 61 + 62 + ip -net ${nsrouter} link set veth1 up 63 + ip -net ${nsrouter} addr add 10.0.2.1/24 dev veth1 64 + ip -net ${nsrouter} addr add dead:2::1/64 dev veth1 65 + 66 + ip -net ${ns1} link set lo up 67 + ip -net ${ns1} link set eth0 up 68 + 69 + ip -net ${ns2} link set lo up 70 + ip -net ${ns2} link set eth0 up 71 + 72 + ip -net ${ns1} addr add 10.0.1.99/24 dev eth0 73 + ip -net ${ns1} addr add dead:1::99/64 dev eth0 74 + ip -net ${ns1} route add default via 10.0.1.1 75 + ip -net ${ns1} route add default via dead:1::1 76 + 77 + ip -net ${ns2} addr add 10.0.2.99/24 dev eth0 78 + ip -net ${ns2} addr add dead:2::99/64 dev eth0 79 + ip -net ${ns2} route add default via 10.0.2.1 80 + ip -net ${ns2} route add default via dead:2::1 81 + 82 + load_ruleset() { 83 + local name=$1 84 + local prio=$2 85 + 86 + ip netns exec ${nsrouter} nft -f - <<EOF 87 + table inet $name { 88 + chain nfq { 89 + ip protocol icmp queue bypass 90 + icmpv6 type { "echo-request", "echo-reply" } queue num 1 bypass 91 + } 92 + chain pre { 93 + type filter hook prerouting priority $prio; policy accept; 94 + jump nfq 95 + } 96 + chain input { 97 + type filter hook input priority $prio; policy accept; 98 + jump nfq 99 + } 100 + chain forward { 101 + type filter hook forward priority $prio; policy accept; 102 + tcp dport 12345 queue num 2 103 + jump nfq 104 + } 105 + chain output { 106 + type filter hook output priority $prio; policy accept; 107 + tcp dport 12345 queue num 3 108 + jump nfq 109 + } 110 + chain post { 111 + type filter hook postrouting priority $prio; policy accept; 112 + jump nfq 113 + } 114 + } 115 + EOF 116 + } 117 + 118 + load_counter_ruleset() { 119 + local prio=$1 120 + 121 + ip netns exec ${nsrouter} nft -f - <<EOF 122 + table inet countrules { 123 + chain pre { 124 + type filter hook prerouting priority $prio; policy accept; 125 + counter 126 + } 127 + chain input { 128 + type filter hook input priority $prio; policy accept; 129 + counter 130 + } 131 + chain forward { 132 + type filter hook forward priority $prio; policy accept; 133 + counter 134 + } 135 + chain output { 136 + type filter hook output priority $prio; policy accept; 137 + counter 138 + } 139 + chain post { 140 + type filter hook postrouting priority $prio; policy accept; 141 + counter 142 + } 143 + } 144 + EOF 145 + } 146 + 147 + test_ping() { 148 + ip netns exec ${ns1} ping -c 1 -q 10.0.2.99 > /dev/null 149 + if [ $? -ne 0 ];then 150 + return 1 151 + fi 152 + 153 + ip netns exec ${ns1} ping -c 1 -q dead:2::99 > /dev/null 154 + if [ $? -ne 0 ];then 155 + return 1 156 + fi 157 + 158 + return 0 159 + } 160 + 161 + test_ping_router() { 162 + ip netns exec ${ns1} ping -c 1 -q 10.0.2.1 > /dev/null 163 + if [ $? -ne 0 ];then 164 + return 1 165 + fi 166 + 167 + ip netns exec ${ns1} ping -c 1 -q dead:2::1 > /dev/null 168 + if [ $? -ne 0 ];then 169 + return 1 170 + fi 171 + 172 + return 0 173 + } 174 + 175 + test_queue_blackhole() { 176 + local proto=$1 177 + 178 + ip netns exec ${nsrouter} nft -f - <<EOF 179 + table $proto blackh { 180 + chain forward { 181 + type filter hook forward priority 0; policy accept; 182 + queue num 600 183 + } 184 + } 185 + EOF 186 + if [ $proto = "ip" ] ;then 187 + ip netns exec ${ns1} ping -c 1 -q 10.0.2.99 > /dev/null 188 + lret=$? 189 + elif [ $proto = "ip6" ]; then 190 + ip netns exec ${ns1} ping -c 1 -q dead:2::99 > /dev/null 191 + lret=$? 192 + else 193 + lret=111 194 + fi 195 + 196 + # queue without bypass keyword should drop traffic if no listener exists. 197 + if [ $lret -eq 0 ];then 198 + echo "FAIL: $proto expected failure, got $lret" 1>&2 199 + exit 1 200 + fi 201 + 202 + ip netns exec ${nsrouter} nft delete table $proto blackh 203 + if [ $? -ne 0 ] ;then 204 + echo "FAIL: $proto: Could not delete blackh table" 205 + exit 1 206 + fi 207 + 208 + echo "PASS: $proto: statement with no listener results in packet drop" 209 + } 210 + 211 + test_queue() 212 + { 213 + local expected=$1 214 + local last="" 215 + 216 + # spawn nf-queue listeners 217 + ip netns exec ${nsrouter} ./nf-queue -c -q 0 -t 3 > "$TMPFILE0" & 218 + ip netns exec ${nsrouter} ./nf-queue -c -q 1 -t 3 > "$TMPFILE1" & 219 + sleep 1 220 + test_ping 221 + ret=$? 222 + if [ $ret -ne 0 ];then 223 + echo "FAIL: netns routing/connectivity with active listener on queue $queue: $ret" 1>&2 224 + exit $ret 225 + fi 226 + 227 + test_ping_router 228 + ret=$? 229 + if [ $ret -ne 0 ];then 230 + echo "FAIL: netns router unreachable listener on queue $queue: $ret" 1>&2 231 + exit $ret 232 + fi 233 + 234 + wait 235 + ret=$? 236 + 237 + for file in $TMPFILE0 $TMPFILE1; do 238 + last=$(tail -n1 "$file") 239 + if [ x"$last" != x"$expected packets total" ]; then 240 + echo "FAIL: Expected $expected packets total, but got $last" 1>&2 241 + cat "$file" 1>&2 242 + 243 + ip netns exec ${nsrouter} nft list ruleset 244 + exit 1 245 + fi 246 + done 247 + 248 + echo "PASS: Expected and received $last" 249 + } 250 + 251 + test_tcp_forward() 252 + { 253 + ip netns exec ${nsrouter} ./nf-queue -q 2 -t 10 & 254 + local nfqpid=$! 255 + 256 + tmpfile=$(mktemp) || exit 1 257 + dd conv=sparse status=none if=/dev/zero bs=1M count=100 of=$tmpfile 258 + ip netns exec ${ns2} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null & 259 + local rpid=$! 260 + 261 + sleep 1 262 + ip netns exec ${ns1} nc -w 5 10.0.2.99 12345 <"$tmpfile" >/dev/null & 263 + 264 + rm -f "$tmpfile" 265 + 266 + wait $rpid 267 + wait $lpid 268 + [ $? -eq 0 ] && echo "PASS: tcp and nfqueue in forward chain" 269 + } 270 + 271 + test_tcp_localhost() 272 + { 273 + tc -net "${nsrouter}" qdisc add dev lo root netem loss random 1% 274 + 275 + tmpfile=$(mktemp) || exit 1 276 + 277 + dd conv=sparse status=none if=/dev/zero bs=1M count=900 of=$tmpfile 278 + ip netns exec ${nsrouter} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null & 279 + local rpid=$! 280 + 281 + ip netns exec ${nsrouter} ./nf-queue -q 3 -t 30 & 282 + local nfqpid=$! 283 + 284 + sleep 1 285 + ip netns exec ${nsrouter} nc -w 5 127.0.0.1 12345 <"$tmpfile" > /dev/null 286 + rm -f "$tmpfile" 287 + 288 + wait $rpid 289 + [ $? -eq 0 ] && echo "PASS: tcp via loopback" 290 + } 291 + 292 + ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null 293 + ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null 294 + ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null 295 + 296 + load_ruleset "filter" 0 297 + 298 + sleep 3 299 + 300 + test_ping 301 + ret=$? 302 + if [ $ret -eq 0 ];then 303 + # queue bypass works (rules were skipped, no listener) 304 + echo "PASS: ${ns1} can reach ${ns2}" 305 + else 306 + echo "FAIL: ${ns1} cannot reach ${ns2}: $ret" 1>&2 307 + exit $ret 308 + fi 309 + 310 + test_queue_blackhole ip 311 + test_queue_blackhole ip6 312 + 313 + # dummy ruleset to add base chains between the 314 + # queueing rules. We don't want the second reinject 315 + # to re-execute the old hooks. 316 + load_counter_ruleset 10 317 + 318 + # we are hooking all: prerouting/input/forward/output/postrouting. 319 + # we ping ${ns2} from ${ns1} via ${nsrouter} using ipv4 and ipv6, so: 320 + # 1x icmp prerouting,forward,postrouting -> 3 queue events (6 incl. reply). 321 + # 1x icmp prerouting,input,output postrouting -> 4 queue events incl. reply. 322 + # so we expect that userspace program receives 10 packets. 323 + test_queue 10 324 + 325 + # same. We queue to a second program as well. 326 + load_ruleset "filter2" 20 327 + test_queue 20 328 + 329 + test_tcp_forward 330 + test_tcp_localhost 331 + 332 + exit $ret