History

mptcp: add mptcp reset option support

The MPTCP reset option allows to carry a mptcp-specific error code that provides more information on the nature of a connection reset. Reset option data received gets stored in the subflow context so it can be sent to userspace via the 'subflow closed' netlink event. When a subflow is closed, the desired error code that should be sent to the peer is also placed in the subflow context structure. If a reset is sent before subflow establishment could complete, e.g. on HMAC failure during an MP_JOIN operation, the mptcp skb extension is used to store the reset information.

Florian Westphal committed 5 years ago

Commit dc87efd1 parent 781bf139 files · +180 −19Browse files

Unified · Split

9 files
  1. include/net/mptcp.h +16 −2
  2. include/uapi/linux/mptcp.h +11 −0
  3. net/ipv4/tcp_ipv4.c +18 −3
  4. net/ipv6/tcp_ipv6.c +13 −1
  5. net/mptcp/options.c +62 −5
  6. net/mptcp/pm_netlink.c +12 −0
  7. net/mptcp/protocol.c +9 −3
  8. net/mptcp/protocol.h +13 −1
  9. net/mptcp/subflow.c +26 −4
include/net/mptcp.h+16−2
@@ -30,8 +30,8 @@ struct mptcp_ext { · 29 unmodified lines
3030 ack64:1,
3131 mpc_map:1,
3232 frozen:1,
33− __unused:1;
34− /* one byte hole */
33+ reset_transient:1;
34+ u8 reset_reason:4;
3535 };
3636
3737 #define MPTCP_RM_IDS_MAX 8
@@ -58,6 +58,8 @@ struct mptcp_out_options { · 20 unmodified lines
5858 struct mptcp_rm_list rm_list;
5959 u8 join_id;
6060 u8 backup;
61+ u8 reset_reason:4;
62+ u8 reset_transient:1;
6163 u32 nonce;
6264 u64 thmac;
6365 u32 token;
@@ -156,6 +158,16 @@ void mptcp_seq_show(struct seq_file *seq); · 92 unmodified lines
156158 int mptcp_subflow_init_cookie_req(struct request_sock *req,
157159 const struct sock *sk_listener,
158160 struct sk_buff *skb);
161+
162+__be32 mptcp_get_reset_option(const struct sk_buff *skb);
163+
164+static inline __be32 mptcp_reset_option(const struct sk_buff *skb)
165+{
166+ if (skb_ext_exist(skb, SKB_EXT_MPTCP))
167+ return mptcp_get_reset_option(skb);
168+
169+ return htonl(0u);
170+}
159171 #else
160172
161173 static inline void mptcp_init(void)
@@ -236,6 +248,8 @@ static inline int mptcp_subflow_init_cookie_req(struct request_sock *req, · 74 unmodified lines
236248 {
237249 return 0; /* TCP fallback */
238250 }
251+
252+static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }
239253 #endif /* CONFIG_MPTCP */
240254
241255 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
include/uapi/linux/mptcp.h+11−0
@@ -174,10 +174,21 @@ enum mptcp_event_attr { · 173 unmodified lines
174174 MPTCP_ATTR_FLAGS, /* u16 */
175175 MPTCP_ATTR_TIMEOUT, /* u32 */
176176 MPTCP_ATTR_IF_IDX, /* s32 */
177+ MPTCP_ATTR_RESET_REASON,/* u32 */
178+ MPTCP_ATTR_RESET_FLAGS, /* u32 */
177179
178180 __MPTCP_ATTR_AFTER_LAST
179181 };
180182
181183 #define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1)
182184
185+/* MPTCP Reset reason codes, rfc8684 */
186+#define MPTCP_RST_EUNSPEC 0
187+#define MPTCP_RST_EMPTCP 1
188+#define MPTCP_RST_ERESOURCE 2
189+#define MPTCP_RST_EPROHIBIT 3
190+#define MPTCP_RST_EWQ2BIG 4
191+#define MPTCP_RST_EBADPERF 5
192+#define MPTCP_RST_EMIDDLEBOX 6
193+
183194 #endif /* _UAPI_MPTCP_H */
net/ipv4/tcp_ipv4.c+18−3
@@ -655,14 +655,18 @@ EXPORT_SYMBOL(tcp_v4_send_check); · 654 unmodified lines
655655 * Exception: precedence violation. We do not implement it in any case.
656656 */
657657
658+#ifdef CONFIG_TCP_MD5SIG
659+#define OPTION_BYTES TCPOLEN_MD5SIG_ALIGNED
660+#else
661+#define OPTION_BYTES sizeof(__be32)
662+#endif
663+
658664 static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb)
659665 {
660666 const struct tcphdr *th = tcp_hdr(skb);
661667 struct {
662668 struct tcphdr th;
663−#ifdef CONFIG_TCP_MD5SIG
664− __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)];
665−#endif
669+ __be32 opt[OPTION_BYTES / sizeof(__be32)];
666670 } rep;
667671 struct ip_reply_arg arg;
668672 #ifdef CONFIG_TCP_MD5SIG
@@ -770,6 +774,17 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) · 101 unmodified lines
770774 ip_hdr(skb)->daddr, &rep.th);
771775 }
772776 #endif
777+ /* Can't co-exist with TCPMD5, hence check rep.opt[0] */
778+ if (rep.opt[0] == 0) {
779+ __be32 mrst = mptcp_reset_option(skb);
780+
781+ if (mrst) {
782+ rep.opt[0] = mrst;
783+ arg.iov[0].iov_len += sizeof(mrst);
784+ rep.th.doff = arg.iov[0].iov_len / 4;
785+ }
786+ }
787+
773788 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
774789 ip_hdr(skb)->saddr, /* XXX */
775790 arg.iov[0].iov_len, IPPROTO_TCP, 0);
net/ipv6/tcp_ipv6.c+13−1
@@ -879,8 +879,8 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 · 878 unmodified lines
879879 struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev);
880880 struct sock *ctl_sk = net->ipv6.tcp_sk;
881881 unsigned int tot_len = sizeof(struct tcphdr);
882+ __be32 mrst = 0, *topt;
882883 struct dst_entry *dst;
883− __be32 *topt;
884884 __u32 mark = 0;
885885
886886 if (tsecr)
@@ -890,6 +890,15 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 · 3 unmodified lines
890890 tot_len += TCPOLEN_MD5SIG_ALIGNED;
891891 #endif
892892
893+#ifdef CONFIG_MPTCP
894+ if (rst && !key) {
895+ mrst = mptcp_reset_option(skb);
896+
897+ if (mrst)
898+ tot_len += sizeof(__be32);
899+ }
900+#endif
901+
893902 buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
894903 GFP_ATOMIC);
895904 if (!buff)
@@ -920,6 +929,9 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 · 24 unmodified lines
920929 *topt++ = htonl(tsecr);
921930 }
922931
932+ if (mrst)
933+ *topt++ = mrst;
934+
923935 #ifdef CONFIG_TCP_MD5SIG
924936 if (key) {
925937 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
net/mptcp/options.c+62−5
@@ -305,6 +305,18 @@ static void mptcp_parse_option(const struct sk_buff *skb, · 304 unmodified lines
305305 mp_opt->fastclose = 1;
306306 break;
307307
308+ case MPTCPOPT_RST:
309+ if (opsize != TCPOLEN_MPTCP_RST)
310+ break;
311+
312+ if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST))
313+ break;
314+ mp_opt->reset = 1;
315+ flags = *ptr++;
316+ mp_opt->reset_transient = flags & MPTCP_RST_TRANSIENT;
317+ mp_opt->reset_reason = *ptr;
318+ break;
319+
308320 default:
309321 break;
310322 }
@@ -327,6 +339,7 @@ void mptcp_get_options(const struct sk_buff *skb, · 16 unmodified lines
327339 mp_opt->rm_addr = 0;
328340 mp_opt->dss = 0;
329341 mp_opt->mp_prio = 0;
342+ mp_opt->reset = 0;
330343
331344 length = (th->doff * 4) - sizeof(struct tcphdr);
332345 ptr = (const unsigned char *)(th + 1);
@@ -726,6 +739,22 @@ static bool mptcp_established_options_mp_prio(struct sock *sk, · 393 unmodified lines
726739 return true;
727740 }
728741
742+static noinline void mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb,
743+ unsigned int *size,
744+ unsigned int remaining,
745+ struct mptcp_out_options *opts)
746+{
747+ const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
748+
749+ if (remaining < TCPOLEN_MPTCP_RST)
750+ return;
751+
752+ *size = TCPOLEN_MPTCP_RST;
753+ opts->suboptions |= OPTION_MPTCP_RST;
754+ opts->reset_transient = subflow->reset_transient;
755+ opts->reset_reason = subflow->reset_reason;
756+}
757+
729758 bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
730759 unsigned int *size, unsigned int remaining,
731760 struct mptcp_out_options *opts)
@@ -741,11 +770,10 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb, · 9 unmodified lines
741770 if (unlikely(__mptcp_check_fallback(msk)))
742771 return false;
743772
744− /* prevent adding of any MPTCP related options on reset packet
745− * until we support MP_TCPRST/MP_FASTCLOSE
746− */
747− if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST))
748− return false;
773+ if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) {
774+ mptcp_established_options_rst(sk, skb, size, remaining, opts);
775+ return true;
776+ }
749777
750778 snd_data_fin = mptcp_data_fin_enabled(msk);
751779 if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, remaining, opts))
@@ -1062,6 +1090,12 @@ void mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) · 310 unmodified lines
10621090 mp_opt.mp_prio = 0;
10631091 }
10641092
1093+ if (mp_opt.reset) {
1094+ subflow->reset_seen = 1;
1095+ subflow->reset_reason = mp_opt.reset_reason;
1096+ subflow->reset_transient = mp_opt.reset_transient;
1097+ }
1098+
10651099 if (!mp_opt.dss)
10661100 return;
10671101
@@ -1289,6 +1323,12 @@ mp_capable_done: · 221 unmodified lines
12891323 ptr += 5;
12901324 }
12911325
1326+ if (OPTION_MPTCP_RST & opts->suboptions)
1327+ *ptr++ = mptcp_option(MPTCPOPT_RST,
1328+ TCPOLEN_MPTCP_RST,
1329+ opts->reset_transient,
1330+ opts->reset_reason);
1331+
12921332 if (opts->ext_copy.use_ack || opts->ext_copy.use_map) {
12931333 struct mptcp_ext *mpext = &opts->ext_copy;
12941334 u8 len = TCPOLEN_MPTCP_DSS_BASE;
@@ -1340,3 +1380,20 @@ mp_capable_done: · 45 unmodified lines
13401380 if (tp)
13411381 mptcp_set_rwin(tp);
13421382 }
1383+
1384+__be32 mptcp_get_reset_option(const struct sk_buff *skb)
1385+{
1386+ const struct mptcp_ext *ext = mptcp_get_ext(skb);
1387+ u8 flags, reason;
1388+
1389+ if (ext) {
1390+ flags = ext->reset_transient;
1391+ reason = ext->reset_reason;
1392+
1393+ return mptcp_option(MPTCPOPT_RST, TCPOLEN_MPTCP_RST,
1394+ flags, reason);
1395+ }
1396+
1397+ return htonl(0u);
1398+}
1399+EXPORT_SYMBOL_GPL(mptcp_get_reset_option);
net/mptcp/pm_netlink.c+12−0
@@ -1687,9 +1687,21 @@ static int mptcp_event_sub_closed(struct sk_buff *skb, · 1686 unmodified lines
16871687 const struct mptcp_sock *msk,
16881688 const struct sock *ssk)
16891689 {
1690+ const struct mptcp_subflow_context *sf;
1691+
16901692 if (mptcp_event_put_token_and_ssk(skb, msk, ssk))
16911693 return -EMSGSIZE;
16921694
1695+ sf = mptcp_subflow_ctx(ssk);
1696+ if (!sf->reset_seen)
1697+ return 0;
1698+
1699+ if (nla_put_u32(skb, MPTCP_ATTR_RESET_REASON, sf->reset_reason))
1700+ return -EMSGSIZE;
1701+
1702+ if (nla_put_u32(skb, MPTCP_ATTR_RESET_FLAGS, sf->reset_transient))
1703+ return -EMSGSIZE;
1704+
16931705 return 0;
16941706 }
16951707
net/mptcp/protocol.c+9−3
@@ -3090,14 +3090,18 @@ bool mptcp_finish_join(struct sock *ssk) · 3089 unmodified lines
30903090 pr_debug("msk=%p, subflow=%p", msk, subflow);
30913091
30923092 /* mptcp socket already closing? */
3093− if (!mptcp_is_fully_established(parent))
3093+ if (!mptcp_is_fully_established(parent)) {
3094+ subflow->reset_reason = MPTCP_RST_EMPTCP;
30943095 return false;
3096+ }
30953097
30963098 if (!msk->pm.server_side)
30973099 goto out;
30983100
3099− if (!mptcp_pm_allow_new_subflow(msk))
3101+ if (!mptcp_pm_allow_new_subflow(msk)) {
3102+ subflow->reset_reason = MPTCP_RST_EPROHIBIT;
31003103 return false;
3104+ }
31013105
31023106 /* active connections are already on conn_list, and we can't acquire
31033107 * msk lock here.
@@ -3111,8 +3115,10 @@ bool mptcp_finish_join(struct sock *ssk) · 7 unmodified lines
31113115 sock_hold(ssk);
31123116 }
31133117 spin_unlock_bh(&msk->join_list_lock);
3114− if (!ret)
3118+ if (!ret) {
3119+ subflow->reset_reason = MPTCP_RST_EPROHIBIT;
31153120 return false;
3121+ }
31163122
31173123 /* attach to msk socket only after we are sure he will deal with us
31183124 * at close time
net/mptcp/protocol.h+13−1
@@ -26,6 +26,7 @@ · 25 unmodified lines
2626 #define OPTION_MPTCP_RM_ADDR BIT(8)
2727 #define OPTION_MPTCP_FASTCLOSE BIT(9)
2828 #define OPTION_MPTCP_PRIO BIT(10)
29+#define OPTION_MPTCP_RST BIT(11)
2930
3031 /* MPTCP option subtypes */
3132 #define MPTCPOPT_MP_CAPABLE 0
@@ -36,6 +37,7 @@ · 4 unmodified lines
3637 #define MPTCPOPT_MP_PRIO 5
3738 #define MPTCPOPT_MP_FAIL 6
3839 #define MPTCPOPT_MP_FASTCLOSE 7
40+#define MPTCPOPT_RST 8
3941
4042 /* MPTCP suboption lengths */
4143 #define TCPOLEN_MPTCP_MPC_SYN 4
@@ -65,6 +67,7 @@ · 23 unmodified lines
6567 #define TCPOLEN_MPTCP_PRIO 3
6668 #define TCPOLEN_MPTCP_PRIO_ALIGN 4
6769 #define TCPOLEN_MPTCP_FASTCLOSE 12
70+#define TCPOLEN_MPTCP_RST 4
6871
6972 /* MPTCP MP_JOIN flags */
7073 #define MPTCPOPT_BACKUP BIT(0)
@@ -94,6 +97,9 @@ · 23 unmodified lines
9497 /* MPTCP MP_PRIO flags */
9598 #define MPTCP_PRIO_BKUP BIT(0)
9699
100+/* MPTCP TCPRST flags */
101+#define MPTCP_RST_TRANSIENT BIT(0)
102+
97103 /* MPTCP socket flags */
98104 #define MPTCP_DATA_READY 0
99105 #define MPTCP_NOSPACE 1
@@ -123,6 +129,7 @@ struct mptcp_options_received { · 23 unmodified lines
123129 u16 mp_capable : 1,
124130 mp_join : 1,
125131 fastclose : 1,
132+ reset : 1,
126133 dss : 1,
127134 add_addr : 1,
128135 rm_addr : 1,
@@ -152,6 +159,8 @@ struct mptcp_options_received { · 23 unmodified lines
152159 };
153160 u64 ahmac;
154161 u16 port;
162+ u8 reset_reason:4;
163+ u8 reset_transient:1;
155164 };
156165
157166 static inline __be32 mptcp_option(u8 subopt, u8 len, u8 nib, u8 field)
@@ -422,6 +431,9 @@ struct mptcp_subflow_context { · 264 unmodified lines
422431 u8 hmac[MPTCPOPT_HMAC_LEN];
423432 u8 local_id;
424433 u8 remote_id;
434+ u8 reset_seen:1;
435+ u8 reset_transient:1;
436+ u8 reset_reason:4;
425437
426438 long delegated_status;
427439 struct list_head delegated_node; /* link into delegated_action, protected by local BH */
@@ -742,7 +754,7 @@ unsigned int mptcp_pm_get_add_addr_accept_max(struct mptcp_sock *msk); · 314 unmodified lines
742754 unsigned int mptcp_pm_get_subflows_max(struct mptcp_sock *msk);
743755 unsigned int mptcp_pm_get_local_addr_max(struct mptcp_sock *msk);
744756
745−static inline struct mptcp_ext *mptcp_get_ext(struct sk_buff *skb)
757+static inline struct mptcp_ext *mptcp_get_ext(const struct sk_buff *skb)
746758 {
747759 return (struct mptcp_ext *)skb_ext_find(skb, SKB_EXT_MPTCP);
748760 }
net/mptcp/subflow.c+26−4
@@ -115,6 +115,16 @@ static bool subflow_use_different_sport(struct mptcp_sock *msk, const struct soc · 114 unmodified lines
115115 return inet_sk(sk)->inet_sport != inet_sk((struct sock *)msk)->inet_sport;
116116 }
117117
118+static void subflow_add_reset_reason(struct sk_buff *skb, u8 reason)
119+{
120+ struct mptcp_ext *mpext = skb_ext_add(skb, SKB_EXT_MPTCP);
121+
122+ if (mpext) {
123+ memset(mpext, 0, sizeof(*mpext));
124+ mpext->reset_reason = reason;
125+ }
126+}
127+
118128 /* Init mptcp request socket.
119129 *
120130 * Returns an error code if a JOIN has failed and a TCP reset
@@ -190,8 +200,10 @@ again: · 69 unmodified lines
190200 subflow_req->msk = subflow_token_join_request(req);
191201
192202 /* Can't fall back to TCP in this case. */
193− if (!subflow_req->msk)
203+ if (!subflow_req->msk) {
204+ subflow_add_reset_reason(skb, MPTCP_RST_EMPTCP);
194205 return -EPERM;
206+ }
195207
196208 if (subflow_use_different_sport(subflow_req->msk, sk_listener)) {
197209 pr_debug("syn inet_sport=%d %d",
@@ -400,8 +412,10 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) · 202 unmodified lines
400412 } else if (subflow->request_join) {
401413 u8 hmac[SHA256_DIGEST_SIZE];
402414
403− if (!mp_opt.mp_join)
415+ if (!mp_opt.mp_join) {
416+ subflow->reset_reason = MPTCP_RST_EMPTCP;
404417 goto do_reset;
418+ }
405419
406420 subflow->thmac = mp_opt.thmac;
407421 subflow->remote_nonce = mp_opt.nonce;
@@ -410,6 +424,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb) · 2 unmodified lines
410424
411425 if (!subflow_thmac_valid(subflow)) {
412426 MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_JOINACKMAC);
427+ subflow->reset_reason = MPTCP_RST_EMPTCP;
413428 goto do_reset;
414429 }
415430
@@ -438,6 +453,7 @@ fallback: · 22 unmodified lines
438453 return;
439454
440455 do_reset:
456+ subflow->reset_transient = 0;
441457 mptcp_subflow_reset(sk);
442458 }
443459
@@ -654,8 +670,10 @@ create_child: · 210 unmodified lines
654670 * to reset the context to non MPTCP status.
655671 */
656672 if (!ctx || fallback) {
657− if (fallback_is_fatal)
673+ if (fallback_is_fatal) {
674+ subflow_add_reset_reason(skb, MPTCP_RST_EMPTCP);
658675 goto dispose_child;
676+ }
659677
660678 subflow_drop_ctx(child);
661679 goto out;
@@ -690,8 +708,10 @@ create_child: · 28 unmodified lines
690708 struct mptcp_sock *owner;
691709
692710 owner = subflow_req->msk;
693− if (!owner)
711+ if (!owner) {
712+ subflow_add_reset_reason(skb, MPTCP_RST_EPROHIBIT);
694713 goto dispose_child;
714+ }
695715
696716 /* move the msk reference ownership to the subflow */
697717 subflow_req->msk = NULL;
@@ -1056,6 +1076,8 @@ fatal: · 358 unmodified lines
10561076 smp_wmb();
10571077 ssk->sk_error_report(ssk);
10581078 tcp_set_state(ssk, TCP_CLOSE);
1079+ subflow->reset_transient = 0;
1080+ subflow->reset_reason = MPTCP_RST_EMPTCP;
10591081 tcp_send_active_reset(ssk, GFP_ATOMIC);
10601082 subflow->data_avail = 0;
10611083 return false;