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        static u32 mptcp_join_hash_secret __read_mostly;
  41        struct tcphdr *th = tcp_hdr(skb);
  42        u32 seq, i;
  43
  44        net_get_random_once(&mptcp_join_hash_secret,
  45                            sizeof(mptcp_join_hash_secret));
  46
  47        if (th->syn)
  48                seq = TCP_SKB_CB(skb)->seq;
  49        else
  50                seq = TCP_SKB_CB(skb)->seq - 1;
  51
  52        i = jhash_3words(seq, net_hash_mix(net),
  53                         (__force __u32)th->source << 16 | (__force __u32)th->dest,
  54                         mptcp_join_hash_secret);
  55
  56        return i % ARRAY_SIZE(join_entries);
  57}
  58
  59static void mptcp_join_store_state(struct join_entry *entry,
  60                                   const struct mptcp_subflow_request_sock *subflow_req)
  61{
  62        entry->token = subflow_req->token;
  63        entry->remote_nonce = subflow_req->remote_nonce;
  64        entry->local_nonce = subflow_req->local_nonce;
  65        entry->backup = subflow_req->backup;
  66        entry->join_id = subflow_req->remote_id;
  67        entry->local_id = subflow_req->local_id;
  68        entry->valid = 1;
  69}
  70
  71void subflow_init_req_cookie_join_save(const struct mptcp_subflow_request_sock *subflow_req,
  72                                       struct sk_buff *skb)
  73{
  74        struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
  75        u32 i = mptcp_join_entry_hash(skb, net);
  76
  77        /* No use in waiting if other cpu is already using this slot --
  78         * would overwrite the data that got stored.
  79         */
  80        spin_lock_bh(&join_entry_locks[i]);
  81        mptcp_join_store_state(&join_entries[i], subflow_req);
  82        spin_unlock_bh(&join_entry_locks[i]);
  83}
  84
  85/* Called for a cookie-ack with MP_JOIN option present.
  86 * Look up the saved state based on skb hash & check token matches msk
  87 * in same netns.
  88 *
  89 * Caller will check msk can still accept another subflow.  The hmac
  90 * present in the cookie ACK mptcp option space will be checked later.
  91 */
  92bool mptcp_token_join_cookie_init_state(struct mptcp_subflow_request_sock *subflow_req,
  93                                        struct sk_buff *skb)
  94{
  95        struct net *net = read_pnet(&subflow_req->sk.req.ireq_net);
  96        u32 i = mptcp_join_entry_hash(skb, net);
  97        struct mptcp_sock *msk;
  98        struct join_entry *e;
  99
 100        e = &join_entries[i];
 101
 102        spin_lock_bh(&join_entry_locks[i]);
 103
 104        if (e->valid == 0) {
 105                spin_unlock_bh(&join_entry_locks[i]);
 106                return false;
 107        }
 108
 109        e->valid = 0;
 110
 111        msk = mptcp_token_get_sock(e->token);
 112        if (!msk) {
 113                spin_unlock_bh(&join_entry_locks[i]);
 114                return false;
 115        }
 116
 117        /* If this fails, the token got re-used in the mean time by another
 118         * mptcp socket in a different netns, i.e. entry is outdated.
 119         */
 120        if (!net_eq(sock_net((struct sock *)msk), net))
 121                goto err_put;
 122
 123        subflow_req->remote_nonce = e->remote_nonce;
 124        subflow_req->local_nonce = e->local_nonce;
 125        subflow_req->backup = e->backup;
 126        subflow_req->remote_id = e->join_id;
 127        subflow_req->token = e->token;
 128        subflow_req->msk = msk;
 129        spin_unlock_bh(&join_entry_locks[i]);
 130        return true;
 131
 132err_put:
 133        spin_unlock_bh(&join_entry_locks[i]);
 134        sock_put((struct sock *)msk);
 135        return false;
 136}
 137
 138void __init mptcp_join_cookie_init(void)
 139{
 140        int i;
 141
 142        for (i = 0; i < COOKIE_JOIN_SLOTS; i++)
 143                spin_lock_init(&join_entry_locks[i]);
 144}
 145