* [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp @ 2023-10-01 15:07 Xin Long 2023-10-02 14:59 ` Xin Long ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: Xin Long @ 2023-10-01 15:07 UTC (permalink / raw) To: network dev, netfilter-devel, linux-sctp Cc: davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal, Marcelo Ricardo Leitner In Scenario A and B below, as the delayed INIT_ACK always changes the peer vtag, SCTP ct with the incorrect vtag may cause packet loss. Scenario A: INIT_ACK is delayed until the peer receives its own INIT_ACK 192.168.1.2 > 192.168.1.1: [INIT] [init tag: 1328086772] 192.168.1.1 > 192.168.1.2: [INIT] [init tag: 1414468151] 192.168.1.2 > 192.168.1.1: [INIT ACK] [init tag: 1328086772] 192.168.1.1 > 192.168.1.2: [INIT ACK] [init tag: 1650211246] * 192.168.1.2 > 192.168.1.1: [COOKIE ECHO] 192.168.1.1 > 192.168.1.2: [COOKIE ECHO] 192.168.1.2 > 192.168.1.1: [COOKIE ACK] Scenario B: INIT_ACK is delayed until the peer completes its own handshake 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 3922216408] 192.168.1.1 > 192.168.1.2: sctp (1) [INIT] [init tag: 144230885] 192.168.1.2 > 192.168.1.1: sctp (1) [INIT ACK] [init tag: 3922216408] 192.168.1.1 > 192.168.1.2: sctp (1) [COOKIE ECHO] 192.168.1.2 > 192.168.1.1: sctp (1) [COOKIE ACK] 192.168.1.1 > 192.168.1.2: sctp (1) [INIT ACK] [init tag: 3914796021] * This patch fixes it as below: In SCTP_CID_INIT processing: - clear ct->proto.sctp.init[!dir] if ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]. (Scenario E) - set ct->proto.sctp.init[dir]. In SCTP_CID_INIT_ACK processing: - drop it if !ct->proto.sctp.init[!dir] && ct->proto.sctp.vtag[!dir] && ct->proto.sctp.vtag[!dir] != ih->init_tag. (Scenario B, Scenario C) - drop it if ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && ct->proto.sctp.vtag[!dir] != ih->init_tag. (Scenario A) In SCTP_CID_COOKIE_ACK processing: - clear ct->proto.sctp.init[dir] and ct->proto.sctp.init[!dir]. (Scenario D) Also, it's important to allow the ct state to move forward with cookie_echo and cookie_ack from the opposite dir for the collision scenarios. There are also other Scenarios where it should allow the packet through, addressed by the processing above: Scenario C: new CT is created by INIT_ACK. Scenario D: start INIT on the existing ESTABLISHED ct. Scenario E: start INIT after the old collision on the existing ESTABLISHED ct. 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 3922216408] 192.168.1.1 > 192.168.1.2: sctp (1) [INIT] [init tag: 144230885] (both side are stopped, then start new connection again in hours) 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 242308742] Signed-off-by: Xin Long <lucien.xin@gmail.com> --- include/linux/netfilter/nf_conntrack_sctp.h | 1 + net/netfilter/nf_conntrack_proto_sctp.c | 41 ++++++++++++++++----- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/linux/netfilter/nf_conntrack_sctp.h index 625f491b95de..fb31312825ae 100644 --- a/include/linux/netfilter/nf_conntrack_sctp.h +++ b/include/linux/netfilter/nf_conntrack_sctp.h @@ -9,6 +9,7 @@ struct ip_ct_sctp { enum sctp_conntrack state; __be32 vtag[IP_CT_DIR_MAX]; + u8 init[IP_CT_DIR_MAX]; u8 last_dir; u8 flags; }; diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index b6bcc8f2f46b..91aee286d503 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -112,7 +112,7 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA}, /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't have Stale cookie*/ /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL},/* 5.2.4 - Big TODO */ -/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */ +/* cookie_ack */ {sCL, sCL, sCW, sES, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */ /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL}, /* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, /* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, @@ -126,7 +126,7 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV}, /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV}, /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV}, -/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */ +/* cookie_echo */ {sIV, sCL, sCE, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */ /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV}, /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV}, /* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, @@ -412,6 +412,9 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, /* (D) vtag must be same as init_vtag as found in INIT_ACK */ if (sh->vtag != ct->proto.sctp.vtag[dir]) goto out_unlock; + } else if (sch->type == SCTP_CID_COOKIE_ACK) { + ct->proto.sctp.init[dir] = 0; + ct->proto.sctp.init[!dir] = 0; } else if (sch->type == SCTP_CID_HEARTBEAT) { if (ct->proto.sctp.vtag[dir] == 0) { pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir); @@ -461,16 +464,18 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, } /* If it is an INIT or an INIT ACK note down the vtag */ - if (sch->type == SCTP_CID_INIT || - sch->type == SCTP_CID_INIT_ACK) { - struct sctp_inithdr _inithdr, *ih; + if (sch->type == SCTP_CID_INIT) { + struct sctp_inithdr _ih, *ih; - ih = skb_header_pointer(skb, offset + sizeof(_sch), - sizeof(_inithdr), &_inithdr); + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); if (ih == NULL) goto out_unlock; - pr_debug("Setting vtag %x for dir %d\n", - ih->init_tag, !dir); + + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) + ct->proto.sctp.init[!dir] = 0; + ct->proto.sctp.init[dir] = 1; + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); ct->proto.sctp.vtag[!dir] = ih->init_tag; /* don't renew timeout on init retransmit so @@ -481,6 +486,24 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, old_state == SCTP_CONNTRACK_CLOSED && nf_ct_is_confirmed(ct)) ignore = true; + } else if (sch->type == SCTP_CID_INIT_ACK) { + struct sctp_inithdr _ih, *ih; + u32 vtag; + + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); + if (ih == NULL) + goto out_unlock; + + vtag = ct->proto.sctp.vtag[!dir]; + if (!ct->proto.sctp.init[!dir] && vtag && vtag != ih->init_tag) + goto out_unlock; + /* collision */ + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && + vtag != ih->init_tag) + goto out_unlock; + + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); + ct->proto.sctp.vtag[!dir] = ih->init_tag; } ct->proto.sctp.state = new_state; -- 2.39.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-01 15:07 [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp Xin Long @ 2023-10-02 14:59 ` Xin Long 2023-10-02 15:18 ` Florian Westphal 2023-10-03 12:44 ` Simon Horman 2023-10-03 12:51 ` Simon Horman 2 siblings, 1 reply; 10+ messages in thread From: Xin Long @ 2023-10-02 14:59 UTC (permalink / raw) To: network dev, netfilter-devel, linux-sctp Cc: davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal, Marcelo Ricardo Leitner [-- Attachment #1: Type: text/plain, Size: 8444 bytes --] On Sun, Oct 1, 2023 at 11:07 AM Xin Long <lucien.xin@gmail.com> wrote: > > In Scenario A and B below, as the delayed INIT_ACK always changes the peer > vtag, SCTP ct with the incorrect vtag may cause packet loss. > > Scenario A: INIT_ACK is delayed until the peer receives its own INIT_ACK > > 192.168.1.2 > 192.168.1.1: [INIT] [init tag: 1328086772] > 192.168.1.1 > 192.168.1.2: [INIT] [init tag: 1414468151] > 192.168.1.2 > 192.168.1.1: [INIT ACK] [init tag: 1328086772] > 192.168.1.1 > 192.168.1.2: [INIT ACK] [init tag: 1650211246] * > 192.168.1.2 > 192.168.1.1: [COOKIE ECHO] > 192.168.1.1 > 192.168.1.2: [COOKIE ECHO] > 192.168.1.2 > 192.168.1.1: [COOKIE ACK] > > Scenario B: INIT_ACK is delayed until the peer completes its own handshake > > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 3922216408] > 192.168.1.1 > 192.168.1.2: sctp (1) [INIT] [init tag: 144230885] > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT ACK] [init tag: 3922216408] > 192.168.1.1 > 192.168.1.2: sctp (1) [COOKIE ECHO] > 192.168.1.2 > 192.168.1.1: sctp (1) [COOKIE ACK] > 192.168.1.1 > 192.168.1.2: sctp (1) [INIT ACK] [init tag: 3914796021] * > > This patch fixes it as below: > > In SCTP_CID_INIT processing: > - clear ct->proto.sctp.init[!dir] if ct->proto.sctp.init[dir] && > ct->proto.sctp.init[!dir]. (Scenario E) > - set ct->proto.sctp.init[dir]. > > In SCTP_CID_INIT_ACK processing: > - drop it if !ct->proto.sctp.init[!dir] && ct->proto.sctp.vtag[!dir] && > ct->proto.sctp.vtag[!dir] != ih->init_tag. (Scenario B, Scenario C) > - drop it if ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && > ct->proto.sctp.vtag[!dir] != ih->init_tag. (Scenario A) > > In SCTP_CID_COOKIE_ACK processing: > - clear ct->proto.sctp.init[dir] and ct->proto.sctp.init[!dir]. (Scenario D) > > Also, it's important to allow the ct state to move forward with cookie_echo > and cookie_ack from the opposite dir for the collision scenarios. > > There are also other Scenarios where it should allow the packet through, > addressed by the processing above: > > Scenario C: new CT is created by INIT_ACK. > > Scenario D: start INIT on the existing ESTABLISHED ct. > > Scenario E: start INIT after the old collision on the existing ESTABLISHED ct. > > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 3922216408] > 192.168.1.1 > 192.168.1.2: sctp (1) [INIT] [init tag: 144230885] > (both side are stopped, then start new connection again in hours) > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 242308742] > > Signed-off-by: Xin Long <lucien.xin@gmail.com> > --- > include/linux/netfilter/nf_conntrack_sctp.h | 1 + > net/netfilter/nf_conntrack_proto_sctp.c | 41 ++++++++++++++++----- > 2 files changed, 33 insertions(+), 9 deletions(-) > > diff --git a/include/linux/netfilter/nf_conntrack_sctp.h b/include/linux/netfilter/nf_conntrack_sctp.h > index 625f491b95de..fb31312825ae 100644 > --- a/include/linux/netfilter/nf_conntrack_sctp.h > +++ b/include/linux/netfilter/nf_conntrack_sctp.h > @@ -9,6 +9,7 @@ struct ip_ct_sctp { > enum sctp_conntrack state; > > __be32 vtag[IP_CT_DIR_MAX]; > + u8 init[IP_CT_DIR_MAX]; > u8 last_dir; > u8 flags; > }; > diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c > index b6bcc8f2f46b..91aee286d503 100644 > --- a/net/netfilter/nf_conntrack_proto_sctp.c > +++ b/net/netfilter/nf_conntrack_proto_sctp.c > @@ -112,7 +112,7 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { > /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA, sSA}, > /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't have Stale cookie*/ > /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA, sCL},/* 5.2.4 - Big TODO */ > -/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */ > +/* cookie_ack */ {sCL, sCL, sCW, sES, sES, sSS, sSR, sSA, sCL},/* Can't come in orig dir */ > /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL, sCL}, > /* heartbeat */ {sHS, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, > /* heartbeat_ack*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, > @@ -126,7 +126,7 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = { > /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA, sIV}, > /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA, sIV}, > /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA, sIV}, > -/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */ > +/* cookie_echo */ {sIV, sCL, sCE, sCE, sES, sSS, sSR, sSA, sIV},/* Can't come in reply dir */ > /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA, sIV}, > /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL, sIV}, > /* heartbeat */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS}, > @@ -412,6 +412,9 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, > /* (D) vtag must be same as init_vtag as found in INIT_ACK */ > if (sh->vtag != ct->proto.sctp.vtag[dir]) > goto out_unlock; > + } else if (sch->type == SCTP_CID_COOKIE_ACK) { > + ct->proto.sctp.init[dir] = 0; > + ct->proto.sctp.init[!dir] = 0; > } else if (sch->type == SCTP_CID_HEARTBEAT) { > if (ct->proto.sctp.vtag[dir] == 0) { > pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir); > @@ -461,16 +464,18 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, > } > > /* If it is an INIT or an INIT ACK note down the vtag */ > - if (sch->type == SCTP_CID_INIT || > - sch->type == SCTP_CID_INIT_ACK) { > - struct sctp_inithdr _inithdr, *ih; > + if (sch->type == SCTP_CID_INIT) { > + struct sctp_inithdr _ih, *ih; > > - ih = skb_header_pointer(skb, offset + sizeof(_sch), > - sizeof(_inithdr), &_inithdr); > + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); > if (ih == NULL) > goto out_unlock; > - pr_debug("Setting vtag %x for dir %d\n", > - ih->init_tag, !dir); > + > + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) > + ct->proto.sctp.init[!dir] = 0; > + ct->proto.sctp.init[dir] = 1; > + > + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); > ct->proto.sctp.vtag[!dir] = ih->init_tag; > > /* don't renew timeout on init retransmit so > @@ -481,6 +486,24 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, > old_state == SCTP_CONNTRACK_CLOSED && > nf_ct_is_confirmed(ct)) > ignore = true; > + } else if (sch->type == SCTP_CID_INIT_ACK) { > + struct sctp_inithdr _ih, *ih; > + u32 vtag; > + > + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); > + if (ih == NULL) > + goto out_unlock; > + > + vtag = ct->proto.sctp.vtag[!dir]; > + if (!ct->proto.sctp.init[!dir] && vtag && vtag != ih->init_tag) > + goto out_unlock; > + /* collision */ > + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && > + vtag != ih->init_tag) > + goto out_unlock; > + > + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); > + ct->proto.sctp.vtag[!dir] = ih->init_tag; > } > > ct->proto.sctp.state = new_state; > -- > 2.39.1 > a reproducer is attached. Thanks. [-- Attachment #2: sctp_collision.sh --] [-- Type: text/x-sh, Size: 5392 bytes --] #!/bin/bash # SPDX-License-Identifier: GPL-2.0 # # Testing For SCTP COLLISION SCENARIO as Below: # # 14:35:47.655279 IP 198.51.200.1.1234 > 198.51.100.1.1234: sctp (1) [INIT] [init tag: 2017837359] # 14:35:48.353250 IP 198.51.100.1.1234 > 198.51.200.1.1234: sctp (1) [INIT] [init tag: 1187206187] # 14:35:48.353275 IP 198.51.200.1.1234 > 198.51.100.1.1234: sctp (1) [INIT ACK] [init tag: 2017837359] # 14:35:48.353283 IP 198.51.100.1.1234 > 198.51.200.1.1234: sctp (1) [COOKIE ECHO] # 14:35:48.353977 IP 198.51.200.1.1234 > 198.51.100.1.1234: sctp (1) [COOKIE ACK] # 14:35:48.855335 IP 198.51.100.1.1234 > 198.51.200.1.1234: sctp (1) [INIT ACK] [init tag: 164579970] # # TOPO: oamcm (link0)<--->(link1) HOST/ROUTER (link2)<--->(link3) oambb # include the c test file in this script cat > ./sctp_test.c << EOF #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> int main(int argc, char *argv[]) { struct sockaddr_in saddr = {}, daddr = {}; int sd, ret, len = sizeof(daddr); struct timeval tv = {25, 0}; char buf[] = "hello"; if (argc != 6 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) { printf("%s <server|client> <LOCAL_IP> <LOCAL_PORT> <REMOTE_IP> <REMOTE_PORT>\n", argv[0]); return -1; } sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); if (sd < 0) { printf("Failed to create sd\n"); return -1; } saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = inet_addr(argv[2]); saddr.sin_port = htons(atoi(argv[3])); ret = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { printf("Failed to bind to address\n"); return -1; } ret = listen(sd, 5); if (ret < 0) { printf("Failed to listen on port\n"); return -1; } daddr.sin_family = AF_INET; daddr.sin_addr.s_addr = inet_addr(argv[4]); daddr.sin_port = htons(atoi(argv[5])); /* make test shorter than 25s */ ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); if (ret < 0) { printf("Failed to setsockopt SO_RCVTIMEO\n"); return -1; } if (!strcmp(argv[1], "server")) { sleep(1); /* wait a bit for client's INIT */ ret = connect(sd, (struct sockaddr *)&daddr, len); if (ret < 0) { printf("Failed to connect to peer\n"); return -1; } ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len); if (ret < 0) { printf("Failed to recv msg %d\n", ret); return -1; } ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len); if (ret < 0) { printf("Failed to send msg %d\n", ret); return -1; } printf("Server: sent! %d\n", ret); } if (!strcmp(argv[1], "client")) { usleep(300000); /* wait a bit for server's listening */ ret = connect(sd, (struct sockaddr *)&daddr, len); if (ret < 0) { printf("Failed to connect to peer\n"); return -1; } sleep(1); /* wait a bit for server's delayed INIT_ACK to reproduce the issue */ ret = sendto(sd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&daddr, len); if (ret < 0) { printf("Failed to send msg %d\n", ret); return -1; } ret = recvfrom(sd, buf, sizeof(buf), 0, (struct sockaddr *)&daddr, &len); if (ret < 0) { printf("Failed to recv msg %d\n", ret); return -1; } printf("Client: rcvd! %d\n", ret); } close(sd); return 0; } EOF if ! conntrack -V; then echo "SKIP: Could not run test without conntrack-tools, try # dnf install -y conntrack-tools" exit 4 fi if ! make sctp_test; then echo "SKIP: Failed to compile sctp_test.c" exit 4 fi # clean up ip netns del oamcm > /dev/null 2>&1 ip netns del oambb > /dev/null 2>&1 ip link del link1 > /dev/null 2>&1 ip link del link2 > /dev/null 2>&1 conntrack -D -p sctp > /dev/null 2>&1 iptables -F # setup the topo ip netns add oamcm ip netns add oambb ip link add link1 type veth peer name link0 netns oamcm ip link add link2 type veth peer name link3 netns oambb ip -n oamcm link set link0 up ip -n oamcm addr add 198.51.100.1/24 dev link0 ip -n oamcm route add 198.51.200.1 dev link0 via 198.51.100.2 ip link set link1 up ip link set link2 up ip addr add 198.51.100.2/24 dev link1 ip addr add 198.51.200.2/24 dev link2 sysctl -wq net.ipv4.ip_forward=1 ip -n oambb link set link3 up ip -n oambb addr add 198.51.200.1/24 dev link3 ip -n oambb route add 198.51.100.1 dev link3 via 198.51.200.2 # simulate the delay on OVS upcall by setting up a delay for INIT_ACK with tc on oamcm side tc -n oamcm qdisc add dev link0 root handle 1: htb tc -n oamcm class add dev link0 parent 1: classid 1:1 htb rate 100mbit tc -n oamcm filter add dev link0 parent 1: protocol ip u32 match ip protocol 132 0xff match u8 2 0xff at 32 flowid 1:1 tc -n oamcm qdisc add dev link0 parent 1:1 handle 10: netem delay 1200ms # simulate the ctstate check on OVS nf_conntrack iptables -A FORWARD -m state --state INVALID,UNTRACKED -j DROP iptables -A INPUT -p sctp -j DROP # use a smaller number for assoc's max_retrans to reproduce the issue modprobe sctp ip netns exec oambb sysctl -wq net.sctp.association_max_retrans=3 # NOTE: one way to work around the issue is set a smaller hb_interval # ip netns exec oambb sysctl -wq net.sctp.hb_interval=3500 # run the test case echo "Test Started (wait up to 25s):" ip net exec oamcm ./sctp_test server 198.51.100.1 1234 198.51.200.1 1234 & ip net exec oambb ./sctp_test client 198.51.200.1 1234 198.51.100.1 1234 && echo "PASS!" && exit 0 echo "FAIL!" && exit 1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-02 14:59 ` Xin Long @ 2023-10-02 15:18 ` Florian Westphal 2023-10-02 15:39 ` Xin Long 0 siblings, 1 reply; 10+ messages in thread From: Florian Westphal @ 2023-10-02 15:18 UTC (permalink / raw) To: Xin Long Cc: network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal, Marcelo Ricardo Leitner Xin Long <lucien.xin@gmail.com> wrote: > a reproducer is attached. > > Thanks. Do you think its worth it to turn this into a selftest? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-02 15:18 ` Florian Westphal @ 2023-10-02 15:39 ` Xin Long 2023-10-02 16:48 ` Florian Westphal 0 siblings, 1 reply; 10+ messages in thread From: Xin Long @ 2023-10-02 15:39 UTC (permalink / raw) To: Florian Westphal Cc: network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Marcelo Ricardo Leitner On Mon, Oct 2, 2023 at 11:18 AM Florian Westphal <fw@strlen.de> wrote: > > Xin Long <lucien.xin@gmail.com> wrote: > > a reproducer is attached. > > > > Thanks. > > Do you think its worth it to turn this into a selftest? I think so, it's a typical SCTP collision scenario, if it's okay to you I'd like to add this to: tools/testing/selftests/netfilter/conntrack_sctp_collision.sh should I repost this netfilter patch together with this selftest or I can post this selftest later? Thanks. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-02 15:39 ` Xin Long @ 2023-10-02 16:48 ` Florian Westphal 0 siblings, 0 replies; 10+ messages in thread From: Florian Westphal @ 2023-10-02 16:48 UTC (permalink / raw) To: Xin Long Cc: Florian Westphal, network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Marcelo Ricardo Leitner Xin Long <lucien.xin@gmail.com> wrote: > On Mon, Oct 2, 2023 at 11:18 AM Florian Westphal <fw@strlen.de> wrote: > > > > Xin Long <lucien.xin@gmail.com> wrote: > > > a reproducer is attached. > > > > > > Thanks. > > > > Do you think its worth it to turn this into a selftest? > I think so, it's a typical SCTP collision scenario, if it's okay to you > I'd like to add this to: > > tools/testing/selftests/netfilter/conntrack_sctp_collision.sh LGTM, thanks! > should I repost this netfilter patch together with this selftest or I > can post this selftest later? Posting it later is fine. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-01 15:07 [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp Xin Long 2023-10-02 14:59 ` Xin Long @ 2023-10-03 12:44 ` Simon Horman 2023-10-03 12:51 ` Simon Horman 2 siblings, 0 replies; 10+ messages in thread From: Simon Horman @ 2023-10-03 12:44 UTC (permalink / raw) To: Xin Long Cc: network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal, Marcelo Ricardo Leitner On Sun, Oct 01, 2023 at 11:07:48AM -0400, Xin Long wrote: > In Scenario A and B below, as the delayed INIT_ACK always changes the peer > vtag, SCTP ct with the incorrect vtag may cause packet loss. > > Scenario A: INIT_ACK is delayed until the peer receives its own INIT_ACK > > 192.168.1.2 > 192.168.1.1: [INIT] [init tag: 1328086772] > 192.168.1.1 > 192.168.1.2: [INIT] [init tag: 1414468151] > 192.168.1.2 > 192.168.1.1: [INIT ACK] [init tag: 1328086772] > 192.168.1.1 > 192.168.1.2: [INIT ACK] [init tag: 1650211246] * > 192.168.1.2 > 192.168.1.1: [COOKIE ECHO] > 192.168.1.1 > 192.168.1.2: [COOKIE ECHO] > 192.168.1.2 > 192.168.1.1: [COOKIE ACK] > > Scenario B: INIT_ACK is delayed until the peer completes its own handshake > > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 3922216408] > 192.168.1.1 > 192.168.1.2: sctp (1) [INIT] [init tag: 144230885] > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT ACK] [init tag: 3922216408] > 192.168.1.1 > 192.168.1.2: sctp (1) [COOKIE ECHO] > 192.168.1.2 > 192.168.1.1: sctp (1) [COOKIE ACK] > 192.168.1.1 > 192.168.1.2: sctp (1) [INIT ACK] [init tag: 3914796021] * > > This patch fixes it as below: > > In SCTP_CID_INIT processing: > - clear ct->proto.sctp.init[!dir] if ct->proto.sctp.init[dir] && > ct->proto.sctp.init[!dir]. (Scenario E) > - set ct->proto.sctp.init[dir]. > > In SCTP_CID_INIT_ACK processing: > - drop it if !ct->proto.sctp.init[!dir] && ct->proto.sctp.vtag[!dir] && > ct->proto.sctp.vtag[!dir] != ih->init_tag. (Scenario B, Scenario C) > - drop it if ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && > ct->proto.sctp.vtag[!dir] != ih->init_tag. (Scenario A) > > In SCTP_CID_COOKIE_ACK processing: > - clear ct->proto.sctp.init[dir] and ct->proto.sctp.init[!dir]. (Scenario D) > > Also, it's important to allow the ct state to move forward with cookie_echo > and cookie_ack from the opposite dir for the collision scenarios. > > There are also other Scenarios where it should allow the packet through, > addressed by the processing above: > > Scenario C: new CT is created by INIT_ACK. > > Scenario D: start INIT on the existing ESTABLISHED ct. > > Scenario E: start INIT after the old collision on the existing ESTABLISHED ct. > > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 3922216408] > 192.168.1.1 > 192.168.1.2: sctp (1) [INIT] [init tag: 144230885] > (both side are stopped, then start new connection again in hours) > 192.168.1.2 > 192.168.1.1: sctp (1) [INIT] [init tag: 242308742] > > Signed-off-by: Xin Long <lucien.xin@gmail.com> Hi, as a fix I wonder if this warrants a Fixes tag. Perhaps our old friend: Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-01 15:07 [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp Xin Long 2023-10-02 14:59 ` Xin Long 2023-10-03 12:44 ` Simon Horman @ 2023-10-03 12:51 ` Simon Horman 2023-10-03 14:17 ` Xin Long 2 siblings, 1 reply; 10+ messages in thread From: Simon Horman @ 2023-10-03 12:51 UTC (permalink / raw) To: Xin Long Cc: network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal, Marcelo Ricardo Leitner On Sun, Oct 01, 2023 at 11:07:48AM -0400, Xin Long wrote: ... > @@ -481,6 +486,24 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, > old_state == SCTP_CONNTRACK_CLOSED && > nf_ct_is_confirmed(ct)) > ignore = true; > + } else if (sch->type == SCTP_CID_INIT_ACK) { > + struct sctp_inithdr _ih, *ih; > + u32 vtag; > + > + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); > + if (ih == NULL) > + goto out_unlock; > + > + vtag = ct->proto.sctp.vtag[!dir]; > + if (!ct->proto.sctp.init[!dir] && vtag && vtag != ih->init_tag) > + goto out_unlock; > + /* collision */ > + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && > + vtag != ih->init_tag) The type of vtag is u32. But the type of ct->proto.sctp.vtag[!dir] and init_tag is __be32. This doesn't seem right (and makes Sparse unhappy). > + goto out_unlock; > + > + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); > + ct->proto.sctp.vtag[!dir] = ih->init_tag; > } > > ct->proto.sctp.state = new_state; > -- > 2.39.1 > > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-03 12:51 ` Simon Horman @ 2023-10-03 14:17 ` Xin Long 2023-10-03 14:23 ` Florian Westphal 0 siblings, 1 reply; 10+ messages in thread From: Xin Long @ 2023-10-03 14:17 UTC (permalink / raw) To: Simon Horman Cc: network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal, Marcelo Ricardo Leitner On Tue, Oct 3, 2023 at 8:51 AM Simon Horman <horms@kernel.org> wrote: > > On Sun, Oct 01, 2023 at 11:07:48AM -0400, Xin Long wrote: > > ... > > > @@ -481,6 +486,24 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, > > old_state == SCTP_CONNTRACK_CLOSED && > > nf_ct_is_confirmed(ct)) > > ignore = true; > > + } else if (sch->type == SCTP_CID_INIT_ACK) { > > + struct sctp_inithdr _ih, *ih; > > + u32 vtag; > > + > > + ih = skb_header_pointer(skb, offset + sizeof(_sch), sizeof(*ih), &_ih); > > + if (ih == NULL) > > + goto out_unlock; > > + > > + vtag = ct->proto.sctp.vtag[!dir]; > > + if (!ct->proto.sctp.init[!dir] && vtag && vtag != ih->init_tag) > > + goto out_unlock; > > + /* collision */ > > + if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir] && > > + vtag != ih->init_tag) > > The type of vtag is u32. But the type of ct->proto.sctp.vtag[!dir] and init_tag > is __be32. This doesn't seem right (and makes Sparse unhappy). You're right, I will fix it and re-post with tag: Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") Thanks. > > > + goto out_unlock; > > + > > + pr_debug("Setting vtag %x for dir %d\n", ih->init_tag, !dir); > > + ct->proto.sctp.vtag[!dir] = ih->init_tag; > > } > > > > ct->proto.sctp.state = new_state; > > -- > > 2.39.1 > > > > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-03 14:17 ` Xin Long @ 2023-10-03 14:23 ` Florian Westphal 2023-10-03 14:37 ` Xin Long 0 siblings, 1 reply; 10+ messages in thread From: Florian Westphal @ 2023-10-03 14:23 UTC (permalink / raw) To: Xin Long Cc: Simon Horman, network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal, Marcelo Ricardo Leitner Xin Long <lucien.xin@gmail.com> wrote: > > The type of vtag is u32. But the type of ct->proto.sctp.vtag[!dir] and init_tag > > is __be32. This doesn't seem right (and makes Sparse unhappy). > You're right, I will fix it and re-post with tag: > > Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") I'm fine with this, the bug is likely inherited from ipt_conntrack_sctp.c, but that doesn't exist anymore. Would you also fix up the __be32/u32 confusion? Better to not add more sparse warnings... Thanks! ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp 2023-10-03 14:23 ` Florian Westphal @ 2023-10-03 14:37 ` Xin Long 0 siblings, 0 replies; 10+ messages in thread From: Xin Long @ 2023-10-03 14:37 UTC (permalink / raw) To: Florian Westphal Cc: Simon Horman, network dev, netfilter-devel, linux-sctp, davem, kuba, Eric Dumazet, Paolo Abeni, Pablo Neira Ayuso, Jozsef Kadlecsik, Marcelo Ricardo Leitner On Tue, Oct 3, 2023 at 10:23 AM Florian Westphal <fw@strlen.de> wrote: > > Xin Long <lucien.xin@gmail.com> wrote: > > > The type of vtag is u32. But the type of ct->proto.sctp.vtag[!dir] and init_tag > > > is __be32. This doesn't seem right (and makes Sparse unhappy). > > You're right, I will fix it and re-post with tag: > > > > Fixes: 9fb9cbb1082d ("[NETFILTER]: Add nf_conntrack subsystem.") > > I'm fine with this, the bug is likely inherited from > ipt_conntrack_sctp.c, but that doesn't exist anymore. ah, I see. > > Would you also fix up the __be32/u32 confusion? > > Better to not add more sparse warnings... > yes, I will fix the __be32 one too. Thanks. ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-10-03 14:37 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-10-01 15:07 [PATCH nf] netfilter: handle the connecting collision properly in nf_conntrack_proto_sctp Xin Long 2023-10-02 14:59 ` Xin Long 2023-10-02 15:18 ` Florian Westphal 2023-10-02 15:39 ` Xin Long 2023-10-02 16:48 ` Florian Westphal 2023-10-03 12:44 ` Simon Horman 2023-10-03 12:51 ` Simon Horman 2023-10-03 14:17 ` Xin Long 2023-10-03 14:23 ` Florian Westphal 2023-10-03 14:37 ` Xin Long
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).