The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/tcp_fastopen.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2015 Patrick Kelsey
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * This is a server-side implementation of TCP Fast Open (TFO) [RFC7413].
   29  *
   30  * This implementation is currently considered to be experimental and is not
   31  * included in kernel builds by default.  To include this code, add the
   32  * following line to your kernel config:
   33  *
   34  * options TCP_RFC7413
   35  *
   36  * The generated TFO cookies are the 64-bit output of
   37  * SipHash24(<16-byte-key><client-ip>).  Multiple concurrent valid keys are
   38  * supported so that time-based rolling cookie invalidation policies can be
   39  * implemented in the system.  The default number of concurrent keys is 2.
   40  * This can be adjusted in the kernel config as follows:
   41  *
   42  * options TCP_RFC7413_MAX_KEYS=<num-keys>
   43  *
   44  *
   45  * The following TFO-specific sysctls are defined:
   46  *
   47  * net.inet.tcp.fastopen.acceptany (RW, default 0)
   48  *     When non-zero, all client-supplied TFO cookies will be considered to
   49  *     be valid.
   50  *
   51  * net.inet.tcp.fastopen.autokey (RW, default 120)
   52  *     When this and net.inet.tcp.fastopen.enabled are non-zero, a new key
   53  *     will be automatically generated after this many seconds.
   54  *
   55  * net.inet.tcp.fastopen.enabled (RW, default 0)
   56  *     When zero, no new TFO connections can be created.  On the transition
   57  *     from enabled to disabled, all installed keys are removed.  On the 
   58  *     transition from disabled to enabled, if net.inet.tcp.fastopen.autokey
   59  *     is non-zero and there are no keys installed, a new key will be 
   60  *     generated immediately.  The transition from enabled to disabled does
   61  *     not affect any TFO connections in progress; it only prevents new ones
   62  *     from being made.
   63  *
   64  * net.inet.tcp.fastopen.keylen (RO)
   65  *     The key length in bytes.
   66  *
   67  * net.inet.tcp.fastopen.maxkeys (RO)
   68  *     The maximum number of keys supported.
   69  *
   70  * net.inet.tcp.fastopen.numkeys (RO)
   71  *     The current number of keys installed.
   72  *
   73  * net.inet.tcp.fastopen.setkey (WO)
   74  *     Install a new key by writing net.inet.tcp.fastopen.keylen bytes to this
   75  *     sysctl.
   76  *
   77  *
   78  * In order for TFO connections to be created via a listen socket, that
   79  * socket must have the TCP_FASTOPEN socket option set on it.  This option
   80  * can be set on the socket either before or after the listen() is invoked.
   81  * Clearing this option on a listen socket after it has been set has no
   82  * effect on existing TFO connections or TFO connections in progress; it
   83  * only prevents new TFO connections from being made.
   84  *
   85  * For passively-created sockets, the TCP_FASTOPEN socket option can be
   86  * queried to determine whether the connection was established using TFO.
   87  * Note that connections that are established via a TFO SYN, but that fall
   88  * back to using a non-TFO SYN|ACK will have the TCP_FASTOPEN socket option
   89  * set.
   90  *
   91  * Per the RFC, this implementation limits the number of TFO connections
   92  * that can be in the SYN_RECEIVED state on a per listen-socket basis.
   93  * Whenever this limit is exceeded, requests for new TFO connections are
   94  * serviced as non-TFO requests.  Without such a limit, given a valid TFO
   95  * cookie, an attacker could keep the listen queue in an overflow condition
   96  * using a TFO SYN flood.  This implementation sets the limit at half the
   97  * configured listen backlog.
   98  *
   99  */
  100 
  101 #include <sys/cdefs.h>
  102 __FBSDID("$FreeBSD: releng/10.4/sys/netinet/tcp_fastopen.c 292823 2015-12-28 02:43:12Z pkelsey $");
  103 
  104 #include "opt_inet.h"
  105 
  106 #include <sys/param.h>
  107 #include <sys/kernel.h>
  108 #include <sys/limits.h>
  109 #include <sys/lock.h>
  110 #include <sys/rmlock.h>
  111 #include <sys/socketvar.h>
  112 #include <sys/sysctl.h>
  113 #include <sys/systm.h>
  114 
  115 #include <crypto/siphash/siphash.h>
  116 
  117 #include <net/vnet.h>
  118 
  119 #include <netinet/in.h>
  120 #include <netinet/in_pcb.h>
  121 #include <netinet/tcp_fastopen.h>
  122 #include <netinet/tcp_var.h>
  123 
  124 
  125 #define TCP_FASTOPEN_KEY_LEN    SIPHASH_KEY_LENGTH
  126 
  127 #if !defined(TCP_RFC7413_MAX_KEYS) || (TCP_RFC7413_MAX_KEYS < 1)
  128 #define TCP_FASTOPEN_MAX_KEYS   2
  129 #else
  130 #define TCP_FASTOPEN_MAX_KEYS   TCP_RFC7413_MAX_KEYS
  131 #endif
  132 
  133 struct tcp_fastopen_keylist {
  134         unsigned int newest;
  135         uint8_t key[TCP_FASTOPEN_MAX_KEYS][TCP_FASTOPEN_KEY_LEN];
  136 };
  137 
  138 struct tcp_fastopen_callout {
  139         struct callout c;
  140         struct vnet *v;
  141 };
  142 
  143 SYSCTL_NODE(_net_inet_tcp, OID_AUTO, fastopen, CTLFLAG_RW, 0, "TCP Fast Open");
  144 
  145 static VNET_DEFINE(int, tcp_fastopen_acceptany) = 0;
  146 #define V_tcp_fastopen_acceptany        VNET(tcp_fastopen_acceptany)
  147 SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, acceptany,
  148     CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_fastopen_acceptany), 0,
  149     "Accept any non-empty cookie");
  150 
  151 static VNET_DEFINE(unsigned int, tcp_fastopen_autokey) = 120;
  152 #define V_tcp_fastopen_autokey  VNET(tcp_fastopen_autokey)
  153 static int sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS);
  154 SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, autokey,
  155     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
  156     &sysctl_net_inet_tcp_fastopen_autokey, "IU",
  157     "Number of seconds between auto-generation of a new key; zero disables");
  158 
  159 VNET_DEFINE(unsigned int, tcp_fastopen_enabled) = 0;
  160 static int sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS);
  161 SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, enabled,
  162     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
  163     &sysctl_net_inet_tcp_fastopen_enabled, "IU",
  164     "Enable/disable TCP Fast Open processing");
  165 
  166 SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, keylen,
  167     CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_KEY_LEN,
  168     "Key length in bytes");
  169 
  170 SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, maxkeys,
  171     CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_MAX_KEYS,
  172     "Maximum number of keys supported");
  173 
  174 static VNET_DEFINE(unsigned int, tcp_fastopen_numkeys) = 0;
  175 #define V_tcp_fastopen_numkeys  VNET(tcp_fastopen_numkeys)
  176 SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, numkeys,
  177     CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(tcp_fastopen_numkeys), 0,
  178     "Number of keys installed");
  179 
  180 static int sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS);
  181 SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, setkey,
  182     CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0,
  183     &sysctl_net_inet_tcp_fastopen_setkey, "",
  184     "Install a new key");
  185 
  186 static VNET_DEFINE(struct rmlock, tcp_fastopen_keylock);
  187 #define V_tcp_fastopen_keylock  VNET(tcp_fastopen_keylock)
  188 
  189 #define TCP_FASTOPEN_KEYS_RLOCK(t)      rm_rlock(&V_tcp_fastopen_keylock, (t))
  190 #define TCP_FASTOPEN_KEYS_RUNLOCK(t)    rm_runlock(&V_tcp_fastopen_keylock, (t))
  191 #define TCP_FASTOPEN_KEYS_WLOCK()       rm_wlock(&V_tcp_fastopen_keylock)
  192 #define TCP_FASTOPEN_KEYS_WUNLOCK()     rm_wunlock(&V_tcp_fastopen_keylock)
  193 
  194 static VNET_DEFINE(struct tcp_fastopen_keylist, tcp_fastopen_keys);
  195 #define V_tcp_fastopen_keys     VNET(tcp_fastopen_keys)
  196 
  197 static VNET_DEFINE(struct tcp_fastopen_callout, tcp_fastopen_autokey_ctx);
  198 #define V_tcp_fastopen_autokey_ctx      VNET(tcp_fastopen_autokey_ctx)
  199 
  200 static VNET_DEFINE(uma_zone_t, counter_zone);
  201 #define V_counter_zone                  VNET(counter_zone)
  202 
  203 void
  204 tcp_fastopen_init(void)
  205 {
  206         V_counter_zone = uma_zcreate("tfo", sizeof(unsigned int),
  207             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
  208         rm_init(&V_tcp_fastopen_keylock, "tfo_keylock");
  209         callout_init_rm(&V_tcp_fastopen_autokey_ctx.c,
  210             &V_tcp_fastopen_keylock, 0);
  211         V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
  212 }
  213 
  214 void
  215 tcp_fastopen_destroy(void)
  216 {
  217         callout_drain(&V_tcp_fastopen_autokey_ctx.c);
  218         rm_destroy(&V_tcp_fastopen_keylock);
  219         uma_zdestroy(V_counter_zone);
  220 }
  221 
  222 unsigned int *
  223 tcp_fastopen_alloc_counter(void)
  224 {
  225         unsigned int *counter;
  226         counter = uma_zalloc(V_counter_zone, M_NOWAIT);
  227         if (counter)
  228                 *counter = 1;
  229         return (counter);
  230 }
  231 
  232 void
  233 tcp_fastopen_decrement_counter(unsigned int *counter)
  234 {
  235         if (*counter == 1)
  236                 uma_zfree(V_counter_zone, counter);
  237         else
  238                 atomic_subtract_int(counter, 1);
  239 }
  240 
  241 static void
  242 tcp_fastopen_addkey_locked(uint8_t *key)
  243 {
  244 
  245         V_tcp_fastopen_keys.newest++;
  246         if (V_tcp_fastopen_keys.newest == TCP_FASTOPEN_MAX_KEYS)
  247                 V_tcp_fastopen_keys.newest = 0;
  248         memcpy(V_tcp_fastopen_keys.key[V_tcp_fastopen_keys.newest], key,
  249             TCP_FASTOPEN_KEY_LEN);
  250         if (V_tcp_fastopen_numkeys < TCP_FASTOPEN_MAX_KEYS)
  251                 V_tcp_fastopen_numkeys++;
  252 }
  253 
  254 static void
  255 tcp_fastopen_autokey_locked(void)
  256 {
  257         uint8_t newkey[TCP_FASTOPEN_KEY_LEN];
  258 
  259         arc4rand(newkey, TCP_FASTOPEN_KEY_LEN, 0);
  260         tcp_fastopen_addkey_locked(newkey);
  261 }
  262 
  263 static void
  264 tcp_fastopen_autokey_callout(void *arg)
  265 {
  266         struct tcp_fastopen_callout *ctx = arg;
  267 
  268         CURVNET_SET(ctx->v);
  269         tcp_fastopen_autokey_locked();
  270         callout_reset(&ctx->c, V_tcp_fastopen_autokey * hz,
  271                       tcp_fastopen_autokey_callout, ctx);
  272         CURVNET_RESTORE();
  273 }
  274 
  275 
  276 static uint64_t
  277 tcp_fastopen_make_cookie(uint8_t key[SIPHASH_KEY_LENGTH], struct in_conninfo *inc)
  278 {
  279         SIPHASH_CTX ctx;
  280         uint64_t siphash;
  281 
  282         SipHash24_Init(&ctx);
  283         SipHash_SetKey(&ctx, key);
  284         switch (inc->inc_flags & INC_ISIPV6) {
  285 #ifdef INET
  286         case 0:
  287                 SipHash_Update(&ctx, &inc->inc_faddr, sizeof(inc->inc_faddr));
  288                 break;
  289 #endif
  290 #ifdef INET6
  291         case INC_ISIPV6:
  292                 SipHash_Update(&ctx, &inc->inc6_faddr, sizeof(inc->inc6_faddr));
  293                 break;
  294 #endif
  295         }
  296         SipHash_Final((u_int8_t *)&siphash, &ctx);
  297 
  298         return (siphash);
  299 }
  300 
  301 
  302 /*
  303  * Return values:
  304  *      -1      the cookie is invalid and no valid cookie is available
  305  *       0      the cookie is invalid and the latest cookie has been returned
  306  *       1      the cookie is valid and the latest cookie has been returned
  307  */
  308 int
  309 tcp_fastopen_check_cookie(struct in_conninfo *inc, uint8_t *cookie,
  310     unsigned int len, uint64_t *latest_cookie)
  311 {
  312         struct rm_priotracker tracker;
  313         unsigned int i, key_index;
  314         uint64_t cur_cookie;
  315 
  316         if (V_tcp_fastopen_acceptany) {
  317                 *latest_cookie = 0;
  318                 return (1);
  319         }
  320 
  321         if (len != TCP_FASTOPEN_COOKIE_LEN) {
  322                 if (V_tcp_fastopen_numkeys > 0) {
  323                         *latest_cookie =
  324                             tcp_fastopen_make_cookie(
  325                                 V_tcp_fastopen_keys.key[V_tcp_fastopen_keys.newest],
  326                                 inc);
  327                         return (0);
  328                 }
  329                 return (-1);
  330         }
  331 
  332         /*
  333          * Check against each available key, from newest to oldest.
  334          */
  335         TCP_FASTOPEN_KEYS_RLOCK(&tracker);
  336         key_index = V_tcp_fastopen_keys.newest;
  337         for (i = 0; i < V_tcp_fastopen_numkeys; i++) {
  338                 cur_cookie =
  339                     tcp_fastopen_make_cookie(V_tcp_fastopen_keys.key[key_index],
  340                         inc);
  341                 if (i == 0)
  342                         *latest_cookie = cur_cookie;
  343                 if (memcmp(cookie, &cur_cookie, TCP_FASTOPEN_COOKIE_LEN) == 0) {
  344                         TCP_FASTOPEN_KEYS_RUNLOCK(&tracker);
  345                         return (1);
  346                 }
  347                 if (key_index == 0)
  348                         key_index = TCP_FASTOPEN_MAX_KEYS - 1;
  349                 else
  350                         key_index--;
  351         }
  352         TCP_FASTOPEN_KEYS_RUNLOCK(&tracker);
  353 
  354         return (0);
  355 }
  356 
  357 static int
  358 sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS)
  359 {
  360         int error;
  361         unsigned int new;
  362 
  363         new = V_tcp_fastopen_autokey;
  364         error = sysctl_handle_int(oidp, &new, 0, req);
  365         if (error == 0 && req->newptr) {
  366                 if (new > (INT_MAX / hz))
  367                         return (EINVAL);
  368 
  369                 TCP_FASTOPEN_KEYS_WLOCK();
  370                 if (V_tcp_fastopen_enabled) {
  371                         if (V_tcp_fastopen_autokey && !new)
  372                                 callout_stop(&V_tcp_fastopen_autokey_ctx.c);
  373                         else if (new)
  374                                 callout_reset(&V_tcp_fastopen_autokey_ctx.c,
  375                                     new * hz, tcp_fastopen_autokey_callout,
  376                                     &V_tcp_fastopen_autokey_ctx);
  377                 }
  378                 V_tcp_fastopen_autokey = new;
  379                 TCP_FASTOPEN_KEYS_WUNLOCK();
  380         }
  381 
  382         return (error);
  383 }
  384 
  385 static int
  386 sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS)
  387 {
  388         int error;
  389         unsigned int new;
  390 
  391         new = V_tcp_fastopen_enabled;
  392         error = sysctl_handle_int(oidp, &new, 0, req);
  393         if (error == 0 && req->newptr) {
  394                 if (V_tcp_fastopen_enabled && !new) {
  395                         /* enabled -> disabled */
  396                         TCP_FASTOPEN_KEYS_WLOCK();
  397                         V_tcp_fastopen_numkeys = 0;
  398                         V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
  399                         if (V_tcp_fastopen_autokey)
  400                                 callout_stop(&V_tcp_fastopen_autokey_ctx.c);
  401                         V_tcp_fastopen_enabled = 0;
  402                         TCP_FASTOPEN_KEYS_WUNLOCK();
  403                 } else if (!V_tcp_fastopen_enabled && new) {
  404                         /* disabled -> enabled */
  405                         TCP_FASTOPEN_KEYS_WLOCK();
  406                         if (V_tcp_fastopen_autokey &&
  407                             (V_tcp_fastopen_numkeys == 0)) {
  408                                 tcp_fastopen_autokey_locked();
  409                                 callout_reset(&V_tcp_fastopen_autokey_ctx.c,
  410                                     V_tcp_fastopen_autokey * hz,
  411                                     tcp_fastopen_autokey_callout,
  412                                     &V_tcp_fastopen_autokey_ctx);
  413                         }
  414                         V_tcp_fastopen_enabled = 1;
  415                         TCP_FASTOPEN_KEYS_WUNLOCK();
  416                 }
  417         }
  418         return (error);
  419 }
  420 
  421 static int
  422 sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS)
  423 {
  424         int error;
  425         uint8_t newkey[TCP_FASTOPEN_KEY_LEN];
  426 
  427         if (req->oldptr != NULL || req->oldlen != 0)
  428                 return (EINVAL);
  429         if (req->newptr == NULL)
  430                 return (EPERM);
  431         if (req->newlen != sizeof(newkey))
  432                 return (EINVAL);
  433         error = SYSCTL_IN(req, newkey, sizeof(newkey));
  434         if (error)
  435                 return (error);
  436 
  437         TCP_FASTOPEN_KEYS_WLOCK();
  438         tcp_fastopen_addkey_locked(newkey);
  439         TCP_FASTOPEN_KEYS_WUNLOCK();
  440 
  441         return (0);
  442 }

Cache object: 840dd241e444b2c437979bb8e926c953


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.