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/11.1/sys/netinet/tcp_fastopen.c 304086 2016-08-14 16:57:10Z karels $");
  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/socket.h>
  112 #include <sys/socketvar.h>
  113 #include <sys/sysctl.h>
  114 #include <sys/systm.h>
  115 
  116 #include <crypto/siphash/siphash.h>
  117 
  118 #include <net/vnet.h>
  119 
  120 #include <netinet/in.h>
  121 #include <netinet/in_pcb.h>
  122 #include <netinet/tcp_fastopen.h>
  123 #include <netinet/tcp_var.h>
  124 
  125 
  126 #define TCP_FASTOPEN_KEY_LEN    SIPHASH_KEY_LENGTH
  127 
  128 #if !defined(TCP_RFC7413_MAX_KEYS) || (TCP_RFC7413_MAX_KEYS < 1)
  129 #define TCP_FASTOPEN_MAX_KEYS   2
  130 #else
  131 #define TCP_FASTOPEN_MAX_KEYS   TCP_RFC7413_MAX_KEYS
  132 #endif
  133 
  134 struct tcp_fastopen_keylist {
  135         unsigned int newest;
  136         uint8_t key[TCP_FASTOPEN_MAX_KEYS][TCP_FASTOPEN_KEY_LEN];
  137 };
  138 
  139 struct tcp_fastopen_callout {
  140         struct callout c;
  141         struct vnet *v;
  142 };
  143 
  144 SYSCTL_NODE(_net_inet_tcp, OID_AUTO, fastopen, CTLFLAG_RW, 0, "TCP Fast Open");
  145 
  146 static VNET_DEFINE(int, tcp_fastopen_acceptany) = 0;
  147 #define V_tcp_fastopen_acceptany        VNET(tcp_fastopen_acceptany)
  148 SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, acceptany,
  149     CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_fastopen_acceptany), 0,
  150     "Accept any non-empty cookie");
  151 
  152 static VNET_DEFINE(unsigned int, tcp_fastopen_autokey) = 120;
  153 #define V_tcp_fastopen_autokey  VNET(tcp_fastopen_autokey)
  154 static int sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS);
  155 SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, autokey,
  156     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
  157     &sysctl_net_inet_tcp_fastopen_autokey, "IU",
  158     "Number of seconds between auto-generation of a new key; zero disables");
  159 
  160 VNET_DEFINE(unsigned int, tcp_fastopen_enabled) = 0;
  161 static int sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS);
  162 SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, enabled,
  163     CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW, NULL, 0,
  164     &sysctl_net_inet_tcp_fastopen_enabled, "IU",
  165     "Enable/disable TCP Fast Open processing");
  166 
  167 SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, keylen,
  168     CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_KEY_LEN,
  169     "Key length in bytes");
  170 
  171 SYSCTL_INT(_net_inet_tcp_fastopen, OID_AUTO, maxkeys,
  172     CTLFLAG_RD, SYSCTL_NULL_INT_PTR, TCP_FASTOPEN_MAX_KEYS,
  173     "Maximum number of keys supported");
  174 
  175 static VNET_DEFINE(unsigned int, tcp_fastopen_numkeys) = 0;
  176 #define V_tcp_fastopen_numkeys  VNET(tcp_fastopen_numkeys)
  177 SYSCTL_UINT(_net_inet_tcp_fastopen, OID_AUTO, numkeys,
  178     CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(tcp_fastopen_numkeys), 0,
  179     "Number of keys installed");
  180 
  181 static int sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS);
  182 SYSCTL_PROC(_net_inet_tcp_fastopen, OID_AUTO, setkey,
  183     CTLFLAG_VNET | CTLTYPE_OPAQUE | CTLFLAG_WR, NULL, 0,
  184     &sysctl_net_inet_tcp_fastopen_setkey, "",
  185     "Install a new key");
  186 
  187 static VNET_DEFINE(struct rmlock, tcp_fastopen_keylock);
  188 #define V_tcp_fastopen_keylock  VNET(tcp_fastopen_keylock)
  189 
  190 #define TCP_FASTOPEN_KEYS_RLOCK(t)      rm_rlock(&V_tcp_fastopen_keylock, (t))
  191 #define TCP_FASTOPEN_KEYS_RUNLOCK(t)    rm_runlock(&V_tcp_fastopen_keylock, (t))
  192 #define TCP_FASTOPEN_KEYS_WLOCK()       rm_wlock(&V_tcp_fastopen_keylock)
  193 #define TCP_FASTOPEN_KEYS_WUNLOCK()     rm_wunlock(&V_tcp_fastopen_keylock)
  194 
  195 static VNET_DEFINE(struct tcp_fastopen_keylist, tcp_fastopen_keys);
  196 #define V_tcp_fastopen_keys     VNET(tcp_fastopen_keys)
  197 
  198 static VNET_DEFINE(struct tcp_fastopen_callout, tcp_fastopen_autokey_ctx);
  199 #define V_tcp_fastopen_autokey_ctx      VNET(tcp_fastopen_autokey_ctx)
  200 
  201 static VNET_DEFINE(uma_zone_t, counter_zone);
  202 #define V_counter_zone                  VNET(counter_zone)
  203 
  204 void
  205 tcp_fastopen_init(void)
  206 {
  207         V_counter_zone = uma_zcreate("tfo", sizeof(unsigned int),
  208             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
  209         rm_init(&V_tcp_fastopen_keylock, "tfo_keylock");
  210         callout_init_rm(&V_tcp_fastopen_autokey_ctx.c,
  211             &V_tcp_fastopen_keylock, 0);
  212         V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
  213 }
  214 
  215 void
  216 tcp_fastopen_destroy(void)
  217 {
  218         callout_drain(&V_tcp_fastopen_autokey_ctx.c);
  219         rm_destroy(&V_tcp_fastopen_keylock);
  220         uma_zdestroy(V_counter_zone);
  221 }
  222 
  223 unsigned int *
  224 tcp_fastopen_alloc_counter(void)
  225 {
  226         unsigned int *counter;
  227         counter = uma_zalloc(V_counter_zone, M_NOWAIT);
  228         if (counter)
  229                 *counter = 1;
  230         return (counter);
  231 }
  232 
  233 void
  234 tcp_fastopen_decrement_counter(unsigned int *counter)
  235 {
  236         if (*counter == 1)
  237                 uma_zfree(V_counter_zone, counter);
  238         else
  239                 atomic_subtract_int(counter, 1);
  240 }
  241 
  242 static void
  243 tcp_fastopen_addkey_locked(uint8_t *key)
  244 {
  245 
  246         V_tcp_fastopen_keys.newest++;
  247         if (V_tcp_fastopen_keys.newest == TCP_FASTOPEN_MAX_KEYS)
  248                 V_tcp_fastopen_keys.newest = 0;
  249         memcpy(V_tcp_fastopen_keys.key[V_tcp_fastopen_keys.newest], key,
  250             TCP_FASTOPEN_KEY_LEN);
  251         if (V_tcp_fastopen_numkeys < TCP_FASTOPEN_MAX_KEYS)
  252                 V_tcp_fastopen_numkeys++;
  253 }
  254 
  255 static void
  256 tcp_fastopen_autokey_locked(void)
  257 {
  258         uint8_t newkey[TCP_FASTOPEN_KEY_LEN];
  259 
  260         arc4rand(newkey, TCP_FASTOPEN_KEY_LEN, 0);
  261         tcp_fastopen_addkey_locked(newkey);
  262 }
  263 
  264 static void
  265 tcp_fastopen_autokey_callout(void *arg)
  266 {
  267         struct tcp_fastopen_callout *ctx = arg;
  268 
  269         CURVNET_SET(ctx->v);
  270         tcp_fastopen_autokey_locked();
  271         callout_reset(&ctx->c, V_tcp_fastopen_autokey * hz,
  272                       tcp_fastopen_autokey_callout, ctx);
  273         CURVNET_RESTORE();
  274 }
  275 
  276 
  277 static uint64_t
  278 tcp_fastopen_make_cookie(uint8_t key[SIPHASH_KEY_LENGTH], struct in_conninfo *inc)
  279 {
  280         SIPHASH_CTX ctx;
  281         uint64_t siphash;
  282 
  283         SipHash24_Init(&ctx);
  284         SipHash_SetKey(&ctx, key);
  285         switch (inc->inc_flags & INC_ISIPV6) {
  286 #ifdef INET
  287         case 0:
  288                 SipHash_Update(&ctx, &inc->inc_faddr, sizeof(inc->inc_faddr));
  289                 break;
  290 #endif
  291 #ifdef INET6
  292         case INC_ISIPV6:
  293                 SipHash_Update(&ctx, &inc->inc6_faddr, sizeof(inc->inc6_faddr));
  294                 break;
  295 #endif
  296         }
  297         SipHash_Final((u_int8_t *)&siphash, &ctx);
  298 
  299         return (siphash);
  300 }
  301 
  302 
  303 /*
  304  * Return values:
  305  *      -1      the cookie is invalid and no valid cookie is available
  306  *       0      the cookie is invalid and the latest cookie has been returned
  307  *       1      the cookie is valid and the latest cookie has been returned
  308  */
  309 int
  310 tcp_fastopen_check_cookie(struct in_conninfo *inc, uint8_t *cookie,
  311     unsigned int len, uint64_t *latest_cookie)
  312 {
  313         struct rm_priotracker tracker;
  314         unsigned int i, key_index;
  315         uint64_t cur_cookie;
  316 
  317         if (V_tcp_fastopen_acceptany) {
  318                 *latest_cookie = 0;
  319                 return (1);
  320         }
  321 
  322         if (len != TCP_FASTOPEN_COOKIE_LEN) {
  323                 if (V_tcp_fastopen_numkeys > 0) {
  324                         *latest_cookie =
  325                             tcp_fastopen_make_cookie(
  326                                 V_tcp_fastopen_keys.key[V_tcp_fastopen_keys.newest],
  327                                 inc);
  328                         return (0);
  329                 }
  330                 return (-1);
  331         }
  332 
  333         /*
  334          * Check against each available key, from newest to oldest.
  335          */
  336         TCP_FASTOPEN_KEYS_RLOCK(&tracker);
  337         key_index = V_tcp_fastopen_keys.newest;
  338         for (i = 0; i < V_tcp_fastopen_numkeys; i++) {
  339                 cur_cookie =
  340                     tcp_fastopen_make_cookie(V_tcp_fastopen_keys.key[key_index],
  341                         inc);
  342                 if (i == 0)
  343                         *latest_cookie = cur_cookie;
  344                 if (memcmp(cookie, &cur_cookie, TCP_FASTOPEN_COOKIE_LEN) == 0) {
  345                         TCP_FASTOPEN_KEYS_RUNLOCK(&tracker);
  346                         return (1);
  347                 }
  348                 if (key_index == 0)
  349                         key_index = TCP_FASTOPEN_MAX_KEYS - 1;
  350                 else
  351                         key_index--;
  352         }
  353         TCP_FASTOPEN_KEYS_RUNLOCK(&tracker);
  354 
  355         return (0);
  356 }
  357 
  358 static int
  359 sysctl_net_inet_tcp_fastopen_autokey(SYSCTL_HANDLER_ARGS)
  360 {
  361         int error;
  362         unsigned int new;
  363 
  364         new = V_tcp_fastopen_autokey;
  365         error = sysctl_handle_int(oidp, &new, 0, req);
  366         if (error == 0 && req->newptr) {
  367                 if (new > (INT_MAX / hz))
  368                         return (EINVAL);
  369 
  370                 TCP_FASTOPEN_KEYS_WLOCK();
  371                 if (V_tcp_fastopen_enabled) {
  372                         if (V_tcp_fastopen_autokey && !new)
  373                                 callout_stop(&V_tcp_fastopen_autokey_ctx.c);
  374                         else if (new)
  375                                 callout_reset(&V_tcp_fastopen_autokey_ctx.c,
  376                                     new * hz, tcp_fastopen_autokey_callout,
  377                                     &V_tcp_fastopen_autokey_ctx);
  378                 }
  379                 V_tcp_fastopen_autokey = new;
  380                 TCP_FASTOPEN_KEYS_WUNLOCK();
  381         }
  382 
  383         return (error);
  384 }
  385 
  386 static int
  387 sysctl_net_inet_tcp_fastopen_enabled(SYSCTL_HANDLER_ARGS)
  388 {
  389         int error;
  390         unsigned int new;
  391 
  392         new = V_tcp_fastopen_enabled;
  393         error = sysctl_handle_int(oidp, &new, 0, req);
  394         if (error == 0 && req->newptr) {
  395                 if (V_tcp_fastopen_enabled && !new) {
  396                         /* enabled -> disabled */
  397                         TCP_FASTOPEN_KEYS_WLOCK();
  398                         V_tcp_fastopen_numkeys = 0;
  399                         V_tcp_fastopen_keys.newest = TCP_FASTOPEN_MAX_KEYS - 1;
  400                         if (V_tcp_fastopen_autokey)
  401                                 callout_stop(&V_tcp_fastopen_autokey_ctx.c);
  402                         V_tcp_fastopen_enabled = 0;
  403                         TCP_FASTOPEN_KEYS_WUNLOCK();
  404                 } else if (!V_tcp_fastopen_enabled && new) {
  405                         /* disabled -> enabled */
  406                         TCP_FASTOPEN_KEYS_WLOCK();
  407                         if (V_tcp_fastopen_autokey &&
  408                             (V_tcp_fastopen_numkeys == 0)) {
  409                                 tcp_fastopen_autokey_locked();
  410                                 callout_reset(&V_tcp_fastopen_autokey_ctx.c,
  411                                     V_tcp_fastopen_autokey * hz,
  412                                     tcp_fastopen_autokey_callout,
  413                                     &V_tcp_fastopen_autokey_ctx);
  414                         }
  415                         V_tcp_fastopen_enabled = 1;
  416                         TCP_FASTOPEN_KEYS_WUNLOCK();
  417                 }
  418         }
  419         return (error);
  420 }
  421 
  422 static int
  423 sysctl_net_inet_tcp_fastopen_setkey(SYSCTL_HANDLER_ARGS)
  424 {
  425         int error;
  426         uint8_t newkey[TCP_FASTOPEN_KEY_LEN];
  427 
  428         if (req->oldptr != NULL || req->oldlen != 0)
  429                 return (EINVAL);
  430         if (req->newptr == NULL)
  431                 return (EPERM);
  432         if (req->newlen != sizeof(newkey))
  433                 return (EINVAL);
  434         error = SYSCTL_IN(req, newkey, sizeof(newkey));
  435         if (error)
  436                 return (error);
  437 
  438         TCP_FASTOPEN_KEYS_WLOCK();
  439         tcp_fastopen_addkey_locked(newkey);
  440         TCP_FASTOPEN_KEYS_WUNLOCK();
  441 
  442         return (0);
  443 }

Cache object: d9f5ea8180cf7afd0a2db0590cc3a730


[ 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.