Merge branch 'mptcp-cope-with-syncookie-on-MP_JOINs'
Paolo Abeni says: ==================== mptcp: cope with syncookie on MP_JOINs Currently syncookies on MP_JOIN connections are not handled correctly: the connections fallback to TCP and are kept alive instead of resetting them at fallback time. The first patch propagates the required information up to syn_recv_sock time, and the 2nd patch addresses the unifying the error path for all MP_JOIN requests. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
f3c7a6e0e5
|
@ -249,6 +249,7 @@ struct mptcp_subflow_request_sock {
|
||||||
u64 thmac;
|
u64 thmac;
|
||||||
u32 local_nonce;
|
u32 local_nonce;
|
||||||
u32 remote_nonce;
|
u32 remote_nonce;
|
||||||
|
struct mptcp_sock *msk;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct mptcp_subflow_request_sock *
|
static inline struct mptcp_subflow_request_sock *
|
||||||
|
|
|
@ -69,6 +69,9 @@ static void subflow_req_destructor(struct request_sock *req)
|
||||||
|
|
||||||
pr_debug("subflow_req=%p", subflow_req);
|
pr_debug("subflow_req=%p", subflow_req);
|
||||||
|
|
||||||
|
if (subflow_req->msk)
|
||||||
|
sock_put((struct sock *)subflow_req->msk);
|
||||||
|
|
||||||
if (subflow_req->mp_capable)
|
if (subflow_req->mp_capable)
|
||||||
mptcp_token_destroy_request(subflow_req->token);
|
mptcp_token_destroy_request(subflow_req->token);
|
||||||
tcp_request_sock_ops.destructor(req);
|
tcp_request_sock_ops.destructor(req);
|
||||||
|
@ -86,7 +89,7 @@ static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* validate received token and create truncated hmac and nonce for SYN-ACK */
|
/* validate received token and create truncated hmac and nonce for SYN-ACK */
|
||||||
static bool subflow_token_join_request(struct request_sock *req,
|
static struct mptcp_sock *subflow_token_join_request(struct request_sock *req,
|
||||||
const struct sk_buff *skb)
|
const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
|
||||||
|
@ -97,13 +100,13 @@ static bool subflow_token_join_request(struct request_sock *req,
|
||||||
msk = mptcp_token_get_sock(subflow_req->token);
|
msk = mptcp_token_get_sock(subflow_req->token);
|
||||||
if (!msk) {
|
if (!msk) {
|
||||||
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINNOTOKEN);
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINNOTOKEN);
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_id = mptcp_pm_get_local_id(msk, (struct sock_common *)req);
|
local_id = mptcp_pm_get_local_id(msk, (struct sock_common *)req);
|
||||||
if (local_id < 0) {
|
if (local_id < 0) {
|
||||||
sock_put((struct sock *)msk);
|
sock_put((struct sock *)msk);
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
subflow_req->local_id = local_id;
|
subflow_req->local_id = local_id;
|
||||||
|
|
||||||
|
@ -114,9 +117,7 @@ static bool subflow_token_join_request(struct request_sock *req,
|
||||||
subflow_req->remote_nonce, hmac);
|
subflow_req->remote_nonce, hmac);
|
||||||
|
|
||||||
subflow_req->thmac = get_unaligned_be64(hmac);
|
subflow_req->thmac = get_unaligned_be64(hmac);
|
||||||
|
return msk;
|
||||||
sock_put((struct sock *)msk);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void subflow_init_req(struct request_sock *req,
|
static void subflow_init_req(struct request_sock *req,
|
||||||
|
@ -133,6 +134,7 @@ static void subflow_init_req(struct request_sock *req,
|
||||||
|
|
||||||
subflow_req->mp_capable = 0;
|
subflow_req->mp_capable = 0;
|
||||||
subflow_req->mp_join = 0;
|
subflow_req->mp_join = 0;
|
||||||
|
subflow_req->msk = NULL;
|
||||||
|
|
||||||
#ifdef CONFIG_TCP_MD5SIG
|
#ifdef CONFIG_TCP_MD5SIG
|
||||||
/* no MPTCP if MD5SIG is enabled on this socket or we may run out of
|
/* no MPTCP if MD5SIG is enabled on this socket or we may run out of
|
||||||
|
@ -166,12 +168,9 @@ static void subflow_init_req(struct request_sock *req,
|
||||||
subflow_req->remote_id = mp_opt.join_id;
|
subflow_req->remote_id = mp_opt.join_id;
|
||||||
subflow_req->token = mp_opt.token;
|
subflow_req->token = mp_opt.token;
|
||||||
subflow_req->remote_nonce = mp_opt.nonce;
|
subflow_req->remote_nonce = mp_opt.nonce;
|
||||||
pr_debug("token=%u, remote_nonce=%u", subflow_req->token,
|
subflow_req->msk = subflow_token_join_request(req, skb);
|
||||||
subflow_req->remote_nonce);
|
pr_debug("token=%u, remote_nonce=%u msk=%p", subflow_req->token,
|
||||||
if (!subflow_token_join_request(req, skb)) {
|
subflow_req->remote_nonce, subflow_req->msk);
|
||||||
subflow_req->mp_join = 0;
|
|
||||||
// @@ need to trigger RST
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,10 +353,9 @@ static bool subflow_hmac_valid(const struct request_sock *req,
|
||||||
const struct mptcp_subflow_request_sock *subflow_req;
|
const struct mptcp_subflow_request_sock *subflow_req;
|
||||||
u8 hmac[SHA256_DIGEST_SIZE];
|
u8 hmac[SHA256_DIGEST_SIZE];
|
||||||
struct mptcp_sock *msk;
|
struct mptcp_sock *msk;
|
||||||
bool ret;
|
|
||||||
|
|
||||||
subflow_req = mptcp_subflow_rsk(req);
|
subflow_req = mptcp_subflow_rsk(req);
|
||||||
msk = mptcp_token_get_sock(subflow_req->token);
|
msk = subflow_req->msk;
|
||||||
if (!msk)
|
if (!msk)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -365,12 +363,7 @@ static bool subflow_hmac_valid(const struct request_sock *req,
|
||||||
subflow_req->remote_nonce,
|
subflow_req->remote_nonce,
|
||||||
subflow_req->local_nonce, hmac);
|
subflow_req->local_nonce, hmac);
|
||||||
|
|
||||||
ret = true;
|
return !crypto_memneq(hmac, mp_opt->hmac, MPTCPOPT_HMAC_LEN);
|
||||||
if (crypto_memneq(hmac, mp_opt->hmac, MPTCPOPT_HMAC_LEN))
|
|
||||||
ret = false;
|
|
||||||
|
|
||||||
sock_put((struct sock *)msk);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mptcp_sock_destruct(struct sock *sk)
|
static void mptcp_sock_destruct(struct sock *sk)
|
||||||
|
@ -438,22 +431,25 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,
|
||||||
struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk);
|
struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk);
|
||||||
struct mptcp_subflow_request_sock *subflow_req;
|
struct mptcp_subflow_request_sock *subflow_req;
|
||||||
struct mptcp_options_received mp_opt;
|
struct mptcp_options_received mp_opt;
|
||||||
bool fallback_is_fatal = false;
|
bool fallback, fallback_is_fatal;
|
||||||
struct sock *new_msk = NULL;
|
struct sock *new_msk = NULL;
|
||||||
bool fallback = false;
|
|
||||||
struct sock *child;
|
struct sock *child;
|
||||||
|
|
||||||
pr_debug("listener=%p, req=%p, conn=%p", listener, req, listener->conn);
|
pr_debug("listener=%p, req=%p, conn=%p", listener, req, listener->conn);
|
||||||
|
|
||||||
/* we need later a valid 'mp_capable' value even when options are not
|
/* After child creation we must look for 'mp_capable' even when options
|
||||||
* parsed
|
* are not parsed
|
||||||
*/
|
*/
|
||||||
mp_opt.mp_capable = 0;
|
mp_opt.mp_capable = 0;
|
||||||
if (tcp_rsk(req)->is_mptcp == 0)
|
|
||||||
|
/* hopefully temporary handling for MP_JOIN+syncookie */
|
||||||
|
subflow_req = mptcp_subflow_rsk(req);
|
||||||
|
fallback_is_fatal = subflow_req->mp_join;
|
||||||
|
fallback = !tcp_rsk(req)->is_mptcp;
|
||||||
|
if (fallback)
|
||||||
goto create_child;
|
goto create_child;
|
||||||
|
|
||||||
/* if the sk is MP_CAPABLE, we try to fetch the client key */
|
/* if the sk is MP_CAPABLE, we try to fetch the client key */
|
||||||
subflow_req = mptcp_subflow_rsk(req);
|
|
||||||
if (subflow_req->mp_capable) {
|
if (subflow_req->mp_capable) {
|
||||||
if (TCP_SKB_CB(skb)->seq != subflow_req->ssn_offset + 1) {
|
if (TCP_SKB_CB(skb)->seq != subflow_req->ssn_offset + 1) {
|
||||||
/* here we can receive and accept an in-window,
|
/* here we can receive and accept an in-window,
|
||||||
|
@ -474,12 +470,11 @@ create_msk:
|
||||||
if (!new_msk)
|
if (!new_msk)
|
||||||
fallback = true;
|
fallback = true;
|
||||||
} else if (subflow_req->mp_join) {
|
} else if (subflow_req->mp_join) {
|
||||||
fallback_is_fatal = true;
|
|
||||||
mptcp_get_options(skb, &mp_opt);
|
mptcp_get_options(skb, &mp_opt);
|
||||||
if (!mp_opt.mp_join ||
|
if (!mp_opt.mp_join ||
|
||||||
!subflow_hmac_valid(req, &mp_opt)) {
|
!subflow_hmac_valid(req, &mp_opt)) {
|
||||||
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC);
|
SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_JOINACKMAC);
|
||||||
return NULL;
|
fallback = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,10 +517,12 @@ create_child:
|
||||||
} else if (ctx->mp_join) {
|
} else if (ctx->mp_join) {
|
||||||
struct mptcp_sock *owner;
|
struct mptcp_sock *owner;
|
||||||
|
|
||||||
owner = mptcp_token_get_sock(ctx->token);
|
owner = subflow_req->msk;
|
||||||
if (!owner)
|
if (!owner)
|
||||||
goto dispose_child;
|
goto dispose_child;
|
||||||
|
|
||||||
|
/* move the msk reference ownership to the subflow */
|
||||||
|
subflow_req->msk = NULL;
|
||||||
ctx->conn = (struct sock *)owner;
|
ctx->conn = (struct sock *)owner;
|
||||||
if (!mptcp_finish_join(child))
|
if (!mptcp_finish_join(child))
|
||||||
goto dispose_child;
|
goto dispose_child;
|
||||||
|
|
Loading…
Reference in New Issue