diff mbox series

[v4] mptcp: fix option length of mp_capable syn/ack

Message ID e09a16ecc0d59feb3e070e2ebf4686cf7a87c95a.1575565496.git.dcaratti@redhat.com
State Accepted, archived
Delegated to: Matthieu Baerts
Headers show
Series [v4] mptcp: fix option length of mp_capable syn/ack | expand

Commit Message

Davide Caratti Dec. 5, 2019, 5:07 p.m. UTC
squashto: mptcp: Handle MPTCP TCP options

in current MPTCP, the server sends the client's key back in the syn/ack
packet. Because of that, both tcpdump and packetdrill refuse to parse
the mp_capable option in the syn/ack. Both RFC6824 and RFC6824bis don't
require this in section 3.1, only the server's key should be sent in
the syn/ack.

- change TCPOLEN_MPTCP_MPC_SYNACK from 20 (4+8+8) to 12 (4+8)
- don't write the client's key in mp_capable syn/ack
- adjust tests in mptcp_parse_option() to cope with the changed
  value of TCPOLEN_MPTCP_MPC_SYNACK

3-way handshakes obtained with

 # ./mptcp_connect.sh -4 -c -e tx
 [...]
 # tcpdump -c3 -tnnr ns1-5de04ec0-TGs4tf-ns1-5de04ec0-TGs4tf-MPTCP-MPTCP-10.0.1.1.pcap tcp

unpatched kernel:

 IP 10.0.1.1.49752 > 10.0.1.1.10000: Flags [S], seq 2594718977, win 65535, options [mss 65495,sackOK,TS val 3944347269 ecr 0,nop,wscale 8,mptcp capable {0xf931b304deb39a42}], length 0
 IP 10.0.1.1.10000 > 10.0.1.1.49752: Flags [S.], seq 3996234497, ack 2594718978, win 65535, options [mss 65495,sackOK,TS val 3944347270 ecr 3944347269,nop,wscale 8,mptcp capable[bad opt]>
^^^ bad option
 IP 10.0.1.1.49752 > 10.0.1.1.10000: Flags [.], ack 1, win 256, options [nop,nop,TS val 3944347270 ecr 3944347270,mptcp capable {0xf931b304deb39a42,0x96614f185e633ce}], length 0

patched kernel:

 IP 10.0.1.1.50850 > 10.0.1.1.10000: Flags [S], seq 626898452, win 65495, options [mss 65495,sackOK,TS val 2266878231 ecr 0,nop,wscale 7,mptcp capable {0x7fe37bfd872b9f9f}], length 0
 IP 10.0.1.1.10000 > 10.0.1.1.50850: Flags [S.], seq 3966041155, ack 626898453, win 65483, options [mss 65495,sackOK,TS val 2266878232 ecr 2266878231,nop,wscale 7,mptcp capable {0x8a167e3af39b5fc1}], length 0
^^^ no more bad option
 IP 10.0.1.1.50850 > 10.0.1.1.10000: Flags [.], ack 1, win 512, options [nop,nop,TS val 2266878232 ecr 2266878232,mptcp capable {0x7fe37bfd872b9f9f,0x8a167e3af39b5fc1}], length 0

v2: more conservative behavior when parsing received options
v3: adjust tests in mptcp_parse_option() to catch all possible
    values of MP_CAPABLE option length specified by v0 protocol,
    thanks Matthieu Baerts
v4: avoid copying the receiver key in mptcp_synack_options(),
    thanks Peter Krystad

squashto: "mptcp: Handle MPTCP TCP options"
Fixes: 8fa520f034ed ("mptcp: Handle MPTCP TCP options")
Signed-off-by: Davide Caratti <dcaratti@redhat.com>
---
 net/mptcp/options.c  | 13 +++++--------
 net/mptcp/protocol.h |  2 +-
 2 files changed, 6 insertions(+), 9 deletions(-)

Comments

Peter Krystad Dec. 5, 2019, 6:14 p.m. UTC | #1
Looks good.

Peter.

On Thu, 2019-12-05 at 18:07 +0100, Davide Caratti wrote:
> squashto: mptcp: Handle MPTCP TCP options
> 
> in current MPTCP, the server sends the client's key back in the syn/ack
> packet. Because of that, both tcpdump and packetdrill refuse to parse
> the mp_capable option in the syn/ack. Both RFC6824 and RFC6824bis don't
> require this in section 3.1, only the server's key should be sent in
> the syn/ack.
> 
> - change TCPOLEN_MPTCP_MPC_SYNACK from 20 (4+8+8) to 12 (4+8)
> - don't write the client's key in mp_capable syn/ack
> - adjust tests in mptcp_parse_option() to cope with the changed
>   value of TCPOLEN_MPTCP_MPC_SYNACK
> 
> 3-way handshakes obtained with
> 
>  # ./mptcp_connect.sh -4 -c -e tx
>  [...]
>  # tcpdump -c3 -tnnr ns1-5de04ec0-TGs4tf-ns1-5de04ec0-TGs4tf-MPTCP-MPTCP-10.0.1.1.pcap tcp
> 
> unpatched kernel:
> 
>  IP 10.0.1.1.49752 > 10.0.1.1.10000: Flags [S], seq 2594718977, win 65535, options [mss 65495,sackOK,TS val 3944347269 ecr 0,nop,wscale 8,mptcp capable {0xf931b304deb39a42}], length 0
>  IP 10.0.1.1.10000 > 10.0.1.1.49752: Flags [S.], seq 3996234497, ack 2594718978, win 65535, options [mss 65495,sackOK,TS val 3944347270 ecr 3944347269,nop,wscale 8,mptcp capable[bad opt]>
> ^^^ bad option
>  IP 10.0.1.1.49752 > 10.0.1.1.10000: Flags [.], ack 1, win 256, options [nop,nop,TS val 3944347270 ecr 3944347270,mptcp capable {0xf931b304deb39a42,0x96614f185e633ce}], length 0
> 
> patched kernel:
> 
>  IP 10.0.1.1.50850 > 10.0.1.1.10000: Flags [S], seq 626898452, win 65495, options [mss 65495,sackOK,TS val 2266878231 ecr 0,nop,wscale 7,mptcp capable {0x7fe37bfd872b9f9f}], length 0
>  IP 10.0.1.1.10000 > 10.0.1.1.50850: Flags [S.], seq 3966041155, ack 626898453, win 65483, options [mss 65495,sackOK,TS val 2266878232 ecr 2266878231,nop,wscale 7,mptcp capable {0x8a167e3af39b5fc1}], length 0
> ^^^ no more bad option
>  IP 10.0.1.1.50850 > 10.0.1.1.10000: Flags [.], ack 1, win 512, options [nop,nop,TS val 2266878232 ecr 2266878232,mptcp capable {0x7fe37bfd872b9f9f,0x8a167e3af39b5fc1}], length 0
> 
> v2: more conservative behavior when parsing received options
> v3: adjust tests in mptcp_parse_option() to catch all possible
>     values of MP_CAPABLE option length specified by v0 protocol,
>     thanks Matthieu Baerts
> v4: avoid copying the receiver key in mptcp_synack_options(),
>     thanks Peter Krystad
> 
> squashto: "mptcp: Handle MPTCP TCP options"
> Fixes: 8fa520f034ed ("mptcp: Handle MPTCP TCP options")
> Signed-off-by: Davide Caratti <dcaratti@redhat.com>
> ---
>  net/mptcp/options.c  | 13 +++++--------
>  net/mptcp/protocol.h |  2 +-
>  2 files changed, 6 insertions(+), 9 deletions(-)
> 
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index 98eb0281d196..b150e881ef7b 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -25,7 +25,7 @@ void mptcp_parse_option(const unsigned char *ptr, int opsize,
>  	 */
>  	case MPTCPOPT_MP_CAPABLE:
>  		if (opsize != TCPOLEN_MPTCP_MPC_SYN &&
> -		    opsize != TCPOLEN_MPTCP_MPC_SYNACK)
> +		    opsize != TCPOLEN_MPTCP_MPC_ACK)
>  			break;
>  
>  		mp_opt->version = *ptr++ & MPTCP_VERSION_MASK;
> @@ -57,7 +57,7 @@ void mptcp_parse_option(const unsigned char *ptr, int opsize,
>  		mp_opt->sndr_key = get_unaligned_be64(ptr);
>  		ptr += 8;
>  
> -		if (opsize == TCPOLEN_MPTCP_MPC_SYNACK) {
> +		if (opsize == TCPOLEN_MPTCP_MPC_ACK) {
>  			mp_opt->rcvr_key = get_unaligned_be64(ptr);
>  			ptr += 8;
>  			pr_debug("MP_CAPABLE flags=%x, sndr=%llu, rcvr=%llu",
> @@ -516,11 +516,9 @@ bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
>  	if (subflow_req->mp_capable) {
>  		opts->suboptions = OPTION_MPTCP_MPC_SYNACK;
>  		opts->sndr_key = subflow_req->local_key;
> -		opts->rcvr_key = subflow_req->remote_key;
>  		*size = TCPOLEN_MPTCP_MPC_SYNACK;
> -		pr_debug("req=%p, local_key=%llu, remote_key=%llu",
> -			 subflow_req, subflow_req->local_key,
> -			 subflow_req->remote_key);
> +		pr_debug("req=%p, local_key=%llu",
> +			 subflow_req, subflow_req->local_key);
>  		return true;
>  	} else if (subflow_req->mp_join) {
>  		opts->suboptions = OPTION_MPTCP_MPJ_SYNACK;
> @@ -650,8 +648,7 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
>  				      MPTCP_CAP_HMAC_SHA1);
>  		put_unaligned_be64(opts->sndr_key, ptr);
>  		ptr += 2;
> -		if ((OPTION_MPTCP_MPC_SYNACK |
> -		     OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
> +		if (OPTION_MPTCP_MPC_ACK & opts->suboptions) {
>  			put_unaligned_be64(opts->rcvr_key, ptr);
>  			ptr += 2;
>  		}
> diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
> index acad61c70de9..10347c9b4dff 100644
> --- a/net/mptcp/protocol.h
> +++ b/net/mptcp/protocol.h
> @@ -34,7 +34,7 @@
>  
>  /* MPTCP suboption lengths */
>  #define TCPOLEN_MPTCP_MPC_SYN		12
> -#define TCPOLEN_MPTCP_MPC_SYNACK	20
> +#define TCPOLEN_MPTCP_MPC_SYNACK	12
>  #define TCPOLEN_MPTCP_MPC_ACK		20
>  #define TCPOLEN_MPTCP_MPJ_SYN		12
>  #define TCPOLEN_MPTCP_MPJ_SYNACK	16
diff mbox series

Patch

diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 98eb0281d196..b150e881ef7b 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -25,7 +25,7 @@  void mptcp_parse_option(const unsigned char *ptr, int opsize,
 	 */
 	case MPTCPOPT_MP_CAPABLE:
 		if (opsize != TCPOLEN_MPTCP_MPC_SYN &&
-		    opsize != TCPOLEN_MPTCP_MPC_SYNACK)
+		    opsize != TCPOLEN_MPTCP_MPC_ACK)
 			break;
 
 		mp_opt->version = *ptr++ & MPTCP_VERSION_MASK;
@@ -57,7 +57,7 @@  void mptcp_parse_option(const unsigned char *ptr, int opsize,
 		mp_opt->sndr_key = get_unaligned_be64(ptr);
 		ptr += 8;
 
-		if (opsize == TCPOLEN_MPTCP_MPC_SYNACK) {
+		if (opsize == TCPOLEN_MPTCP_MPC_ACK) {
 			mp_opt->rcvr_key = get_unaligned_be64(ptr);
 			ptr += 8;
 			pr_debug("MP_CAPABLE flags=%x, sndr=%llu, rcvr=%llu",
@@ -516,11 +516,9 @@  bool mptcp_synack_options(const struct request_sock *req, unsigned int *size,
 	if (subflow_req->mp_capable) {
 		opts->suboptions = OPTION_MPTCP_MPC_SYNACK;
 		opts->sndr_key = subflow_req->local_key;
-		opts->rcvr_key = subflow_req->remote_key;
 		*size = TCPOLEN_MPTCP_MPC_SYNACK;
-		pr_debug("req=%p, local_key=%llu, remote_key=%llu",
-			 subflow_req, subflow_req->local_key,
-			 subflow_req->remote_key);
+		pr_debug("req=%p, local_key=%llu",
+			 subflow_req, subflow_req->local_key);
 		return true;
 	} else if (subflow_req->mp_join) {
 		opts->suboptions = OPTION_MPTCP_MPJ_SYNACK;
@@ -650,8 +648,7 @@  void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
 				      MPTCP_CAP_HMAC_SHA1);
 		put_unaligned_be64(opts->sndr_key, ptr);
 		ptr += 2;
-		if ((OPTION_MPTCP_MPC_SYNACK |
-		     OPTION_MPTCP_MPC_ACK) & opts->suboptions) {
+		if (OPTION_MPTCP_MPC_ACK & opts->suboptions) {
 			put_unaligned_be64(opts->rcvr_key, ptr);
 			ptr += 2;
 		}
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index acad61c70de9..10347c9b4dff 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -34,7 +34,7 @@ 
 
 /* MPTCP suboption lengths */
 #define TCPOLEN_MPTCP_MPC_SYN		12
-#define TCPOLEN_MPTCP_MPC_SYNACK	20
+#define TCPOLEN_MPTCP_MPC_SYNACK	12
 #define TCPOLEN_MPTCP_MPC_ACK		20
 #define TCPOLEN_MPTCP_MPJ_SYN		12
 #define TCPOLEN_MPTCP_MPJ_SYNACK	16