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

Merge tag 'nf-23-10-04' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Florian Westphal says:

====================
netfilter patches for net

First patch resolves a regression with vlan header matching, this was
broken since 6.5 release. From myself.

Second patch fixes an ancient problem with sctp connection tracking in
case INIT_ACK packets are delayed. This comes with a selftest, both
patches from Xin Long.

Patch 4 extends the existing nftables audit selftest, from
Phil Sutter.

Patch 5, also from Phil, avoids a situation where nftables
would emit an audit record twice. This was broken since 5.13 days.

Patch 6, from myself, avoids spurious insertion failure if we encounter an
overlapping but expired range during element insertion with the
'nft_set_rbtree' backend. This problem exists since 6.2.

* tag 'nf-23-10-04' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
netfilter: nf_tables: nft_set_rbtree: fix spurious insertion failure
netfilter: nf_tables: Deduplicate nft_register_obj audit logs
selftests: netfilter: Extend nft_audit.sh
selftests: netfilter: test for sctp collision processing in nf_conntrack
netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp
netfilter: nft_payload: rebuild vlan header on h_proto access
====================

Link: https://lore.kernel.org/r/20231004141405.28749-1-fw@strlen.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+395 -62
+1
include/linux/netfilter/nf_conntrack_sctp.h
··· 9 9 enum sctp_conntrack state; 10 10 11 11 __be32 vtag[IP_CT_DIR_MAX]; 12 + u8 init[IP_CT_DIR_MAX]; 12 13 u8 last_dir; 13 14 u8 flags; 14 15 };
+33 -10
net/netfilter/nf_conntrack_proto_sctp.c
··· 112 112 /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA}, 113 113 /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't have Stale cookie*/ 114 114 /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL},/* 5.2.4 - Big TODO */ 115 - /* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */ 115 + /* cookie_ack */ {sCL, sCL, sCW, sES, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */ 116 116 /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL}, 117 117 /* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, 118 118 /* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, ··· 126 126 /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV}, 127 127 /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV}, 128 128 /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV}, 129 - /* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */ 129 + /* cookie_echo */ {sIV, sCL, sCE, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */ 130 130 /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV}, 131 131 /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV}, 132 132 /* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, ··· 412 412 /* (D) vtag must be same as init_vtag as found in INIT_ACK */ 413 413 if (sh->vtag != ct->proto.sctp.vtag[dir]) 414 414 goto out_unlock; 415 + } else if (sch->type == SCTP_CID_COOKIE_ACK) { 416 + ct->proto.sctp.init[dir] = 0; 417 + ct->proto.sctp.init[!dir] = 0; 415 418 } else if (sch->type == SCTP_CID_HEARTBEAT) { 416 419 if (ct->proto.sctp.vtag[dir] == 0) { 417 420 pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir); ··· 464 461 } 465 462 466 463 /* If it is an INIT or an INIT ACK note down the vtag */ 467 - if (sch->type == SCTP_CID_INIT || 468 - sch->type == SCTP_CID_INIT_ACK) { 469 - struct sctp_inithdr _inithdr, *ih; 464 + if (sch->type == SCTP_CID_INIT) { 465 + struct sctp_inithdr _ih, *ih; 470 466 471 - ih = skb_header_pointer(skb, offset + sizeof(_sch), 472 - sizeof(_inithdr), &_inithdr); 473 - if (ih == NULL) 467 + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); 468 + if (!ih) 474 469 goto out_unlock; 475 - pr_debug("Setting vtag %x for dir %d\n", 476 - ih->init_tag, !dir); 470 + 471 + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) 472 + ct->proto.sctp.init[!dir] = 0; 473 + ct->proto.sctp.init[dir] = 1; 474 + 475 + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); 477 476 ct->proto.sctp.vtag[!dir] = ih->init_tag; 478 477 479 478 /* don't renew timeout on init retransmit so ··· 486 481 old_state == SCTP_CONNTRACK_CLOSED && 487 482 nf_ct_is_confirmed(ct)) 488 483 ignore = true; 484 + } else if (sch->type == SCTP_CID_INIT_ACK) { 485 + struct sctp_inithdr _ih, *ih; 486 + __be32 vtag; 487 + 488 + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); 489 + if (!ih) 490 + goto out_unlock; 491 + 492 + vtag = ct->proto.sctp.vtag[!dir]; 493 + if (!ct->proto.sctp.init[!dir] && vtag && vtag != ih->init_tag) 494 + goto out_unlock; 495 + /* collision */ 496 + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && 497 + vtag != ih->init_tag) 498 + goto out_unlock; 499 + 500 + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); 501 + ct->proto.sctp.vtag[!dir] = ih->init_tag; 489 502 } 490 503 491 504 ct->proto.sctp.state = new_state;
+28 -16
net/netfilter/nf_tables_api.c
··· 7871 7871 return nft_delobj(&ctx, obj); 7872 7872 } 7873 7873 7874 - void nft_obj_notify(struct net *net, const struct nft_table *table, 7875 - struct nft_object *obj, u32 portid, u32 seq, int event, 7876 - u16 flags, int family, int report, gfp_t gfp) 7874 + static void 7875 + __nft_obj_notify(struct net *net, const struct nft_table *table, 7876 + struct nft_object *obj, u32 portid, u32 seq, int event, 7877 + u16 flags, int family, int report, gfp_t gfp) 7877 7878 { 7878 7879 struct nftables_pernet *nft_net = nft_pernet(net); 7879 7880 struct sk_buff *skb; 7880 7881 int err; 7881 - char *buf = kasprintf(gfp, "%s:%u", 7882 - table->name, nft_net->base_seq); 7883 - 7884 - audit_log_nfcfg(buf, 7885 - family, 7886 - obj->handle, 7887 - event == NFT_MSG_NEWOBJ ? 7888 - AUDIT_NFT_OP_OBJ_REGISTER : 7889 - AUDIT_NFT_OP_OBJ_UNREGISTER, 7890 - gfp); 7891 - kfree(buf); 7892 7882 7893 7883 if (!report && 7894 7884 !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) ··· 7901 7911 err: 7902 7912 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS); 7903 7913 } 7914 + 7915 + void nft_obj_notify(struct net *net, const struct nft_table *table, 7916 + struct nft_object *obj, u32 portid, u32 seq, int event, 7917 + u16 flags, int family, int report, gfp_t gfp) 7918 + { 7919 + struct nftables_pernet *nft_net = nft_pernet(net); 7920 + char *buf = kasprintf(gfp, "%s:%u", 7921 + table->name, nft_net->base_seq); 7922 + 7923 + audit_log_nfcfg(buf, 7924 + family, 7925 + obj->handle, 7926 + event == NFT_MSG_NEWOBJ ? 7927 + AUDIT_NFT_OP_OBJ_REGISTER : 7928 + AUDIT_NFT_OP_OBJ_UNREGISTER, 7929 + gfp); 7930 + kfree(buf); 7931 + 7932 + __nft_obj_notify(net, table, obj, portid, seq, event, 7933 + flags, family, report, gfp); 7934 + } 7904 7935 EXPORT_SYMBOL_GPL(nft_obj_notify); 7905 7936 7906 7937 static void nf_tables_obj_notify(const struct nft_ctx *ctx, 7907 7938 struct nft_object *obj, int event) 7908 7939 { 7909 - nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, ctx->seq, event, 7910 - ctx->flags, ctx->family, ctx->report, GFP_KERNEL); 7940 + __nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, 7941 + ctx->seq, event, ctx->flags, ctx->family, 7942 + ctx->report, GFP_KERNEL); 7911 7943 } 7912 7944 7913 7945 /*
+12 -1
net/netfilter/nft_payload.c
··· 154 154 return pkt->inneroff; 155 155 } 156 156 157 + static bool nft_payload_need_vlan_copy(const struct nft_payload *priv) 158 + { 159 + unsigned int len = priv->offset + priv->len; 160 + 161 + /* data past ether src/dst requested, copy needed */ 162 + if (len > offsetof(struct ethhdr, h_proto)) 163 + return true; 164 + 165 + return false; 166 + } 167 + 157 168 void nft_payload_eval(const struct nft_expr *expr, 158 169 struct nft_regs *regs, 159 170 const struct nft_pktinfo *pkt) ··· 183 172 goto err; 184 173 185 174 if (skb_vlan_tag_present(skb) && 186 - priv->offset >= offsetof(struct ethhdr, h_proto)) { 175 + nft_payload_need_vlan_copy(priv)) { 187 176 if (!nft_payload_copy_vlan(dest, skb, 188 177 priv->offset, priv->len)) 189 178 goto err;
+29 -17
net/netfilter/nft_set_rbtree.c
··· 233 233 rb_erase(&rbe->node, &priv->root); 234 234 } 235 235 236 - static int nft_rbtree_gc_elem(const struct nft_set *__set, 237 - struct nft_rbtree *priv, 238 - struct nft_rbtree_elem *rbe, 239 - u8 genmask) 236 + static const struct nft_rbtree_elem * 237 + nft_rbtree_gc_elem(const struct nft_set *__set, struct nft_rbtree *priv, 238 + struct nft_rbtree_elem *rbe, u8 genmask) 240 239 { 241 240 struct nft_set *set = (struct nft_set *)__set; 242 241 struct rb_node *prev = rb_prev(&rbe->node); ··· 245 246 246 247 gc = nft_trans_gc_alloc(set, 0, GFP_ATOMIC); 247 248 if (!gc) 248 - return -ENOMEM; 249 + return ERR_PTR(-ENOMEM); 249 250 250 251 /* search for end interval coming before this element. 251 252 * end intervals don't carry a timeout extension, they ··· 260 261 prev = rb_prev(prev); 261 262 } 262 263 264 + rbe_prev = NULL; 263 265 if (prev) { 264 266 rbe_prev = rb_entry(prev, struct nft_rbtree_elem, node); 265 267 nft_rbtree_gc_remove(net, set, priv, rbe_prev); ··· 272 272 */ 273 273 gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); 274 274 if (WARN_ON_ONCE(!gc)) 275 - return -ENOMEM; 275 + return ERR_PTR(-ENOMEM); 276 276 277 277 nft_trans_gc_elem_add(gc, rbe_prev); 278 278 } ··· 280 280 nft_rbtree_gc_remove(net, set, priv, rbe); 281 281 gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); 282 282 if (WARN_ON_ONCE(!gc)) 283 - return -ENOMEM; 283 + return ERR_PTR(-ENOMEM); 284 284 285 285 nft_trans_gc_elem_add(gc, rbe); 286 286 287 287 nft_trans_gc_queue_sync_done(gc); 288 288 289 - return 0; 289 + return rbe_prev; 290 290 } 291 291 292 292 static bool nft_rbtree_update_first(const struct nft_set *set, ··· 314 314 struct nft_rbtree *priv = nft_set_priv(set); 315 315 u8 cur_genmask = nft_genmask_cur(net); 316 316 u8 genmask = nft_genmask_next(net); 317 - int d, err; 317 + int d; 318 318 319 319 /* Descend the tree to search for an existing element greater than the 320 320 * key value to insert that is greater than the new element. This is the ··· 363 363 */ 364 364 if (nft_set_elem_expired(&rbe->ext) && 365 365 nft_set_elem_active(&rbe->ext, cur_genmask)) { 366 - err = nft_rbtree_gc_elem(set, priv, rbe, genmask); 367 - if (err < 0) 368 - return err; 366 + const struct nft_rbtree_elem *removed_end; 367 + 368 + removed_end = nft_rbtree_gc_elem(set, priv, rbe, genmask); 369 + if (IS_ERR(removed_end)) 370 + return PTR_ERR(removed_end); 371 + 372 + if (removed_end == rbe_le || removed_end == rbe_ge) 373 + return -EAGAIN; 369 374 370 375 continue; 371 376 } ··· 491 486 struct nft_rbtree_elem *rbe = elem->priv; 492 487 int err; 493 488 494 - write_lock_bh(&priv->lock); 495 - write_seqcount_begin(&priv->count); 496 - err = __nft_rbtree_insert(net, set, rbe, ext); 497 - write_seqcount_end(&priv->count); 498 - write_unlock_bh(&priv->lock); 489 + do { 490 + if (fatal_signal_pending(current)) 491 + return -EINTR; 492 + 493 + cond_resched(); 494 + 495 + write_lock_bh(&priv->lock); 496 + write_seqcount_begin(&priv->count); 497 + err = __nft_rbtree_insert(net, set, rbe, ext); 498 + write_seqcount_end(&priv->count); 499 + write_unlock_bh(&priv->lock); 500 + } while (err == -EAGAIN); 499 501 500 502 return err; 501 503 }
+3 -2
tools/testing/selftests/netfilter/Makefile
··· 6 6 nft_concat_range.sh nft_conntrack_helper.sh \ 7 7 nft_queue.sh nft_meta.sh nf_nat_edemux.sh \ 8 8 ipip-conntrack-mtu.sh conntrack_tcp_unreplied.sh \ 9 - conntrack_vrf.sh nft_synproxy.sh rpath.sh nft_audit.sh 9 + conntrack_vrf.sh nft_synproxy.sh rpath.sh nft_audit.sh \ 10 + conntrack_sctp_collision.sh 10 11 11 12 HOSTPKG_CONFIG := pkg-config 12 13 13 14 CFLAGS += $(shell $(HOSTPKG_CONFIG) --cflags libmnl 2>/dev/null) 14 15 LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl) 15 16 16 - TEST_GEN_FILES = nf-queue connect_close audit_logread 17 + TEST_GEN_FILES = nf-queue connect_close audit_logread sctp_collision 17 18 18 19 include ../lib.mk
+89
tools/testing/selftests/netfilter/conntrack_sctp_collision.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Testing For SCTP COLLISION SCENARIO as Below: 5 + # 6 + # 14:35:47.655279 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT] [init tag: 2017837359] 7 + # 14:35:48.353250 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT] [init tag: 1187206187] 8 + # 14:35:48.353275 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT ACK] [init tag: 2017837359] 9 + # 14:35:48.353283 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [COOKIE ECHO] 10 + # 14:35:48.353977 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [COOKIE ACK] 11 + # 14:35:48.855335 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT ACK] [init tag: 164579970] 12 + # 13 + # TOPO: SERVER_NS (link0)<--->(link1) ROUTER_NS (link2)<--->(link3) CLIENT_NS 14 + 15 + CLIENT_NS=$(mktemp -u client-XXXXXXXX) 16 + CLIENT_IP="198.51.200.1" 17 + CLIENT_PORT=1234 18 + 19 + SERVER_NS=$(mktemp -u server-XXXXXXXX) 20 + SERVER_IP="198.51.100.1" 21 + SERVER_PORT=1234 22 + 23 + ROUTER_NS=$(mktemp -u router-XXXXXXXX) 24 + CLIENT_GW="198.51.200.2" 25 + SERVER_GW="198.51.100.2" 26 + 27 + # setup the topo 28 + setup() { 29 + ip net add $CLIENT_NS 30 + ip net add $SERVER_NS 31 + ip net add $ROUTER_NS 32 + ip -n $SERVER_NS link add link0 type veth peer name link1 netns $ROUTER_NS 33 + ip -n $CLIENT_NS link add link3 type veth peer name link2 netns $ROUTER_NS 34 + 35 + ip -n $SERVER_NS link set link0 up 36 + ip -n $SERVER_NS addr add $SERVER_IP/24 dev link0 37 + ip -n $SERVER_NS route add $CLIENT_IP dev link0 via $SERVER_GW 38 + 39 + ip -n $ROUTER_NS link set link1 up 40 + ip -n $ROUTER_NS link set link2 up 41 + ip -n $ROUTER_NS addr add $SERVER_GW/24 dev link1 42 + ip -n $ROUTER_NS addr add $CLIENT_GW/24 dev link2 43 + ip net exec $ROUTER_NS sysctl -wq net.ipv4.ip_forward=1 44 + 45 + ip -n $CLIENT_NS link set link3 up 46 + ip -n $CLIENT_NS addr add $CLIENT_IP/24 dev link3 47 + ip -n $CLIENT_NS route add $SERVER_IP dev link3 via $CLIENT_GW 48 + 49 + # simulate the delay on OVS upcall by setting up a delay for INIT_ACK with 50 + # tc on $SERVER_NS side 51 + tc -n $SERVER_NS qdisc add dev link0 root handle 1: htb 52 + tc -n $SERVER_NS class add dev link0 parent 1: classid 1:1 htb rate 100mbit 53 + tc -n $SERVER_NS filter add dev link0 parent 1: protocol ip u32 match ip protocol 132 \ 54 + 0xff match u8 2 0xff at 32 flowid 1:1 55 + tc -n $SERVER_NS qdisc add dev link0 parent 1:1 handle 10: netem delay 1200ms 56 + 57 + # simulate the ctstate check on OVS nf_conntrack 58 + ip net exec $ROUTER_NS iptables -A FORWARD -m state --state INVALID,UNTRACKED -j DROP 59 + ip net exec $ROUTER_NS iptables -A INPUT -p sctp -j DROP 60 + 61 + # use a smaller number for assoc's max_retrans to reproduce the issue 62 + modprobe sctp 63 + ip net exec $CLIENT_NS sysctl -wq net.sctp.association_max_retrans=3 64 + } 65 + 66 + cleanup() { 67 + ip net exec $CLIENT_NS pkill sctp_collision 2>&1 >/dev/null 68 + ip net exec $SERVER_NS pkill sctp_collision 2>&1 >/dev/null 69 + ip net del "$CLIENT_NS" 70 + ip net del "$SERVER_NS" 71 + ip net del "$ROUTER_NS" 72 + } 73 + 74 + do_test() { 75 + ip net exec $SERVER_NS ./sctp_collision server \ 76 + $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT & 77 + ip net exec $CLIENT_NS ./sctp_collision client \ 78 + $CLIENT_IP $CLIENT_PORT $SERVER_IP $SERVER_PORT 79 + } 80 + 81 + # NOTE: one way to work around the issue is set a smaller hb_interval 82 + # ip net exec $CLIENT_NS sysctl -wq net.sctp.hb_interval=3500 83 + 84 + # run the test case 85 + trap cleanup EXIT 86 + setup && \ 87 + echo "Test for SCTP Collision in nf_conntrack:" && \ 88 + do_test && echo "PASS!" 89 + exit $?
+101 -16
tools/testing/selftests/netfilter/nft_audit.sh
··· 12 12 } 13 13 14 14 logfile=$(mktemp) 15 + rulefile=$(mktemp) 15 16 echo "logging into $logfile" 16 17 ./audit_logread >"$logfile" & 17 18 logread_pid=$! 18 - trap 'kill $logread_pid; rm -f $logfile' EXIT 19 + trap 'kill $logread_pid; rm -f $logfile $rulefile' EXIT 19 20 exec 3<"$logfile" 20 21 21 22 do_test() { # (cmd, log) ··· 27 26 res=$(diff -a -u <(echo "$2") - <&3) 28 27 [ $? -eq 0 ] && { echo "OK"; return; } 29 28 echo "FAIL" 30 - echo "$res" 31 - ((RC++)) 29 + grep -v '^\(---\|+++\|@@\)' <<< "$res" 30 + ((RC--)) 32 31 } 33 32 34 33 nft flush ruleset 34 + 35 + # adding tables, chains and rules 35 36 36 37 for table in t1 t2; do 37 38 do_test "nft add table $table" \ ··· 65 62 "table=$table family=2 entries=6 op=nft_register_rule" 66 63 done 67 64 65 + for ((i = 0; i < 500; i++)); do 66 + echo "add rule t2 c3 counter accept comment \"rule $i\"" 67 + done >$rulefile 68 + do_test "nft -f $rulefile" \ 69 + 'table=t2 family=2 entries=500 op=nft_register_rule' 70 + 71 + # adding sets and elements 72 + 73 + settype='type inet_service; counter' 74 + setelem='{ 22, 80, 443 }' 75 + setblock="{ $settype; elements = $setelem; }" 76 + do_test "nft add set t1 s $setblock" \ 77 + "table=t1 family=2 entries=4 op=nft_register_set" 78 + 79 + do_test "nft add set t1 s2 $setblock; add set t1 s3 { $settype; }" \ 80 + "table=t1 family=2 entries=5 op=nft_register_set" 81 + 82 + do_test "nft add element t1 s3 $setelem" \ 83 + "table=t1 family=2 entries=3 op=nft_register_setelem" 84 + 85 + # adding counters 86 + 87 + do_test 'nft add counter t1 c1' \ 88 + 'table=t1 family=2 entries=1 op=nft_register_obj' 89 + 90 + do_test 'nft add counter t2 c1; add counter t2 c2' \ 91 + 'table=t2 family=2 entries=2 op=nft_register_obj' 92 + 93 + # adding/updating quotas 94 + 95 + do_test 'nft add quota t1 q1 { 10 bytes }' \ 96 + 'table=t1 family=2 entries=1 op=nft_register_obj' 97 + 98 + do_test 'nft add quota t2 q1 { 10 bytes }; add quota t2 q2 { 10 bytes }' \ 99 + 'table=t2 family=2 entries=2 op=nft_register_obj' 100 + 101 + # changing the quota value triggers obj update path 102 + do_test 'nft add quota t1 q1 { 20 bytes }' \ 103 + 'table=t1 family=2 entries=1 op=nft_register_obj' 104 + 105 + # resetting rules 106 + 68 107 do_test 'nft reset rules t1 c2' \ 69 108 'table=t1 family=2 entries=3 op=nft_reset_rule' 70 109 ··· 114 69 'table=t1 family=2 entries=3 op=nft_reset_rule 115 70 table=t1 family=2 entries=3 op=nft_reset_rule 116 71 table=t1 family=2 entries=3 op=nft_reset_rule' 117 - 118 - do_test 'nft reset rules' \ 119 - 'table=t1 family=2 entries=3 op=nft_reset_rule 120 - table=t1 family=2 entries=3 op=nft_reset_rule 121 - table=t1 family=2 entries=3 op=nft_reset_rule 122 - table=t2 family=2 entries=3 op=nft_reset_rule 123 - table=t2 family=2 entries=3 op=nft_reset_rule 124 - table=t2 family=2 entries=3 op=nft_reset_rule' 125 - 126 - for ((i = 0; i < 500; i++)); do 127 - echo "add rule t2 c3 counter accept comment \"rule $i\"" 128 - done | do_test 'nft -f -' \ 129 - 'table=t2 family=2 entries=500 op=nft_register_rule' 130 72 131 73 do_test 'nft reset rules t2 c3' \ 132 74 'table=t2 family=2 entries=189 op=nft_reset_rule ··· 136 104 table=t2 family=2 entries=180 op=nft_reset_rule 137 105 table=t2 family=2 entries=188 op=nft_reset_rule 138 106 table=t2 family=2 entries=135 op=nft_reset_rule' 107 + 108 + # resetting sets and elements 109 + 110 + elem=(22 ,80 ,443) 111 + relem="" 112 + for i in {1..3}; do 113 + relem+="${elem[((i - 1))]}" 114 + do_test "nft reset element t1 s { $relem }" \ 115 + "table=t1 family=2 entries=$i op=nft_reset_setelem" 116 + done 117 + 118 + do_test 'nft reset set t1 s' \ 119 + 'table=t1 family=2 entries=3 op=nft_reset_setelem' 120 + 121 + # deleting rules 122 + 123 + readarray -t handles < <(nft -a list chain t1 c1 | \ 124 + sed -n 's/.*counter.* handle \(.*\)$/\1/p') 125 + 126 + do_test "nft delete rule t1 c1 handle ${handles[0]}" \ 127 + 'table=t1 family=2 entries=1 op=nft_unregister_rule' 128 + 129 + cmd='delete rule t1 c1 handle' 130 + do_test "nft $cmd ${handles[1]}; $cmd ${handles[2]}" \ 131 + 'table=t1 family=2 entries=2 op=nft_unregister_rule' 132 + 133 + do_test 'nft flush chain t1 c2' \ 134 + 'table=t1 family=2 entries=3 op=nft_unregister_rule' 135 + 136 + do_test 'nft flush table t2' \ 137 + 'table=t2 family=2 entries=509 op=nft_unregister_rule' 138 + 139 + # deleting chains 140 + 141 + do_test 'nft delete chain t2 c2' \ 142 + 'table=t2 family=2 entries=1 op=nft_unregister_chain' 143 + 144 + # deleting sets and elements 145 + 146 + do_test 'nft delete element t1 s { 22 }' \ 147 + 'table=t1 family=2 entries=1 op=nft_unregister_setelem' 148 + 149 + do_test 'nft delete element t1 s { 80, 443 }' \ 150 + 'table=t1 family=2 entries=2 op=nft_unregister_setelem' 151 + 152 + do_test 'nft flush set t1 s2' \ 153 + 'table=t1 family=2 entries=3 op=nft_unregister_setelem' 154 + 155 + do_test 'nft delete set t1 s2' \ 156 + 'table=t1 family=2 entries=1 op=nft_unregister_set' 157 + 158 + do_test 'nft delete set t1 s3' \ 159 + 'table=t1 family=2 entries=1 op=nft_unregister_set' 139 160 140 161 exit $RC
+99
tools/testing/selftests/netfilter/sctp_collision.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <stdio.h> 4 + #include <stdlib.h> 5 + #include <string.h> 6 + #include <unistd.h> 7 + #include <arpa/inet.h> 8 + 9 + int main(int argc, char *argv[]) 10 + { 11 + struct sockaddr_in saddr = {}, daddr = {}; 12 + int sd, ret, len = sizeof(daddr); 13 + struct timeval tv = {25, 0}; 14 + char buf[] = "hello"; 15 + 16 + if (argc != 6 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) { 17 + printf("%s <server|client> <LOCAL_IP> <LOCAL_PORT> <REMOTE_IP> <REMOTE_PORT>\n", 18 + argv[0]); 19 + return -1; 20 + } 21 + 22 + sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); 23 + if (sd < 0) { 24 + printf("Failed to create sd\n"); 25 + return -1; 26 + } 27 + 28 + saddr.sin_family = AF_INET; 29 + saddr.sin_addr.s_addr = inet_addr(argv[2]); 30 + saddr.sin_port = htons(atoi(argv[3])); 31 + 32 + ret = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)); 33 + if (ret < 0) { 34 + printf("Failed to bind to address\n"); 35 + goto out; 36 + } 37 + 38 + ret = listen(sd, 5); 39 + if (ret < 0) { 40 + printf("Failed to listen on port\n"); 41 + goto out; 42 + } 43 + 44 + daddr.sin_family = AF_INET; 45 + daddr.sin_addr.s_addr = inet_addr(argv[4]); 46 + daddr.sin_port = htons(atoi(argv[5])); 47 + 48 + /* make test shorter than 25s */ 49 + ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 50 + if (ret < 0) { 51 + printf("Failed to setsockopt SO_RCVTIMEO\n"); 52 + goto out; 53 + } 54 + 55 + if (!strcmp(argv[1], "server")) { 56 + sleep(1); /* wait a bit for client's INIT */ 57 + ret = connect(sd, (struct sockaddr *)&daddr, len); 58 + if (ret < 0) { 59 + printf("Failed to connect to peer\n"); 60 + goto out; 61 + } 62 + ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len); 63 + if (ret < 0) { 64 + printf("Failed to recv msg %d\n", ret); 65 + goto out; 66 + } 67 + ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len); 68 + if (ret < 0) { 69 + printf("Failed to send msg %d\n", ret); 70 + goto out; 71 + } 72 + printf("Server: sent! %d\n", ret); 73 + } 74 + 75 + if (!strcmp(argv[1], "client")) { 76 + usleep(300000); /* wait a bit for server's listening */ 77 + ret = connect(sd, (struct sockaddr *)&daddr, len); 78 + if (ret < 0) { 79 + printf("Failed to connect to peer\n"); 80 + goto out; 81 + } 82 + sleep(1); /* wait a bit for server's delayed INIT_ACK to reproduce the issue */ 83 + ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len); 84 + if (ret < 0) { 85 + printf("Failed to send msg %d\n", ret); 86 + goto out; 87 + } 88 + ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len); 89 + if (ret < 0) { 90 + printf("Failed to recv msg %d\n", ret); 91 + goto out; 92 + } 93 + printf("Client: rcvd! %d\n", ret); 94 + } 95 + ret = 0; 96 + out: 97 + close(sd); 98 + return ret; 99 + }