linux/net/mptcp/syncookies.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/skbuff.h>
   3
   4#include "protocol.h"
   5
   6/* Syncookies do not work for JOIN requests.
   7 *
   8 * Unlike MP_CAPABLE, where the ACK cookie contains the needed MPTCP
   9 * options to reconstruct the initial syn state, MP_JOIN does not contain
  10 * the token to obtain the mptcp socket nor the server-generated nonce
  11 * that was used in the cookie SYN/ACK response.
  12 *
  13 * Keep a small best effort state table to store the syn/synack data,
  14 * indexed by skb hash.
  15 *
  16 * A MP_JOIN SYN packet handled by syn cookies is only stored if the 32bit
  17 * token matches a known mptcp connection that can still accept more subflows.
  18 *
  19 * There is no timeout handling -- state is only re-constructed
  20 * when the TCP ACK passed the cookie validation check.
  21 */
  22
  23struct join_entry {
  24        u32 token;
  25        u32 remote_nonce;
  26        u32 local_nonce;
  27        u8 join_id;
  28        u8 local_id;
  29        u8 backup;
  30        u8 valid;
  31};
  32
  33#define COOKIE_JOIN_SLOTS       1024
  34
  35static struct join_entry join_entries[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
  36static spinlock_t join_entry_locks[COOKIE_JOIN_SLOTS] __cacheline_aligned_in_smp;
  37
  38static u32 mptcp_join_entry_hash(struct sk_buff *skb, struct net *net)
  39{
  40        u32 i = skb_get_hash(skb) ^ net_hash_mix(net);
  41
  42        return i % ARRAY_SIZE(join_entries);
  43}
  44
  45static void mptcp_join_store_state(struct join_entry *entry,
  46                                   const struct mptcp_subflow_request_sock *subflow_req)
  47{
  48        entry->token = subflow_req->token;
  49        entry->remote_nonce = subflow_req->remote_nonce;
  50        entry->local_nonce = subflow_req->local_nonce;
  51        entry->backup = subflow_req->backup;
  52        entry->join_id = subflow_req->remote_id;
  53        entry->local_id = subflow_req->local_id;
  54        entry->valid = 1;
  55}
  56
  57void subflow_init_req_cookie_join_save(const struct mptcp_subflow_request_sock *subflow_req,
  58                                       struct sk_buff *skb)
  59{
  60        struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
  61        u32 i = mptcp_join_entry_hash(skb, net);
  62
  63        /* No use in waiting if other cpu is already using this slot --
  64         * would overwrite the data that got stored.
  65         */
  66        spin_lock_bh(&join_entry_locks[i]);
  67        mptcp_join_store_state(&join_entries[i], subflow_req);
  68        spin_unlock_bh(&join_entry_locks[i]);
  69}
  70
  71/* Called for a cookie-ack with MP_JOIN option present.
  72 * Look up the saved state based on skb hash & check token matches msk
  73 * in same netns.
  74 *
  75 * Caller will check msk can still accept another subflow.  The hmac
  76 * present in the cookie ACK mptcp option space will be checked later.
  77 */
  78bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subflow_req,
  79                                        struct sk_buff *skb)
  80{
  81        struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
  82        u32 i = mptcp_join_entry_hash(skb, net);
  83        struct mptcp_sock *msk;
  84        struct join_entry *e;
  85
  86        e = &join_entries[i];
  87
  88        spin_lock_bh(&join_entry_locks[i]);
  89
  90        if (e->valid == 0) {
  91                spin_unlock_bh(&join_entry_locks[i]);
  92                return false;
  93        }
  94
  95        e->valid = 0;
  96
  97        msk = mptcp_token_get_sock(e->token);
  98        if (!msk) {
  99                spin_unlock_bh(&join_entry_locks[i]);
 100                return false;
 101        }
 102
 103        /* If this fails, the token got re-used in the mean time by another
 104         * mptcp socket in a different netns, i.e. entry is outdated.
 105         */
 106        if (!net_eq(sock_net((struct sock *)msk), net))
 107                goto err_put;
 108
 109        subflow_req->remote_nonce = e->remote_nonce;
 110        subflow_req->local_nonce = e->local_nonce;
 111        subflow_req->backup = e->backup;
 112        subflow_req->remote_id = e->join_id;
 113        subflow_req->token = e->token;
 114        subflow_req->msk = msk;
 115        spin_unlock_bh(&join_entry_locks[i]);
 116        return true;
 117
 118err_put:
 119        spin_unlock_bh(&join_entry_locks[i]);
 120        sock_put((struct sock *)msk);
 121        return false;
 122}
 123
 124void __init mptcp_join_cookie_init(void)
 125{
 126        int i;
 127
 128        for (i = 0; i < COOKIE_JOIN_SLOTS; i++)
 129                spin_lock_init(&join_entry_locks[i]);
 130}
 131