LCOV - code coverage report
Current view: top level - net - pf_syncookies.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 135 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: pf_syncookies.c,v 1.7 2018/09/10 15:54:28 henning Exp $ */
       2             : 
       3             : /* Copyright (c) 2016,2017 Henning Brauer <henning@openbsd.org>
       4             :  * Copyright (c) 2016 Alexandr Nedvedicky <sashan@openbsd.org>
       5             :  *
       6             :  * syncookie parts based on FreeBSD sys/netinet/tcp_syncache.c
       7             :  *
       8             :  * Copyright (c) 2001 McAfee, Inc.
       9             :  * Copyright (c) 2006,2013 Andre Oppermann, Internet Business Solutions AG
      10             :  * All rights reserved.
      11             :  *
      12             :  * This software was developed for the FreeBSD Project by Jonathan Lemon
      13             :  * and McAfee Research, the Security Research Division of McAfee, Inc. under
      14             :  * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
      15             :  * DARPA CHATS research program. [2001 McAfee, Inc.]
      16             :  *
      17             :  * Redistribution and use in source and binary forms, with or without
      18             :  * modification, are permitted provided that the following conditions
      19             :  * are met:
      20             :  * 1. Redistributions of source code must retain the above copyright
      21             :  *    notice, this list of conditions and the following disclaimer.
      22             :  * 2. Redistributions in binary form must reproduce the above copyright
      23             :  *    notice, this list of conditions and the following disclaimer in the
      24             :  *    documentation and/or other materials provided with the distribution.
      25             :  *
      26             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      27             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      28             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      29             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      30             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      31             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      32             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      33             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      34             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      35             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      36             :  * SUCH DAMAGE.
      37             :  */
      38             : 
      39             : /*
      40             :  * when we're under synflood, we use syncookies to prevent state table
      41             :  * exhaustion. Trigger for the synflood mode is the number of half-open
      42             :  * connections in the state table.
      43             :  * We leave synflood mode when the number of half-open states - including
      44             :  * in-flight syncookies - drops far enough again
      45             :  */
      46             :  
      47             : /*
      48             :  * syncookie enabled Initial Sequence Number:
      49             :  *  24 bit MAC
      50             :  *   3 bit WSCALE index
      51             :  *   3 bit MSS index
      52             :  *   1 bit SACK permitted
      53             :  *   1 bit odd/even secret
      54             :  *
      55             :  * References:
      56             :  *  RFC4987 TCP SYN Flooding Attacks and Common Mitigations
      57             :  *  http://cr.yp.to/syncookies.html    (overview)
      58             :  *  http://cr.yp.to/syncookies/archive (details)
      59             :  */
      60             : 
      61             : #include "pflog.h"
      62             : 
      63             : #include <sys/param.h>
      64             : #include <sys/systm.h>
      65             : #include <sys/mbuf.h>
      66             : #include <sys/filio.h>
      67             : #include <sys/socket.h>
      68             : #include <sys/socketvar.h>
      69             : #include <sys/kernel.h>
      70             : #include <sys/time.h>
      71             : #include <sys/pool.h>
      72             : #include <sys/proc.h>
      73             : #include <sys/rwlock.h>
      74             : #include <sys/syslog.h>
      75             : 
      76             : #include <net/if.h>
      77             : #include <net/if_var.h>
      78             : #include <net/if_types.h>
      79             : #include <net/route.h>
      80             : 
      81             : #include <netinet/in.h>
      82             : #include <netinet/ip.h>
      83             : #include <netinet/ip_var.h>
      84             : #include <netinet/tcp.h>
      85             : #include <netinet/tcp_seq.h>
      86             : #include <netinet/udp.h>
      87             : #include <netinet/ip_icmp.h>
      88             : #include <netinet/in_pcb.h>
      89             : #include <netinet/tcp_timer.h>
      90             : #include <netinet/tcp_var.h>
      91             : #include <netinet/tcp_fsm.h>
      92             : #include <netinet/udp_var.h>
      93             : #include <netinet/icmp_var.h>
      94             : #include <netinet/ip_divert.h>
      95             : 
      96             : #include <net/pfvar.h>
      97             : #include <net/pfvar_priv.h>
      98             : 
      99             : #if NPFLOG > 0
     100             : #include <net/if_pflog.h>
     101             : #endif  /* NPFLOG > 0 */
     102             : 
     103             : union pf_syncookie {
     104             :         uint8_t         cookie;
     105             :         struct {
     106             :                 uint8_t oddeven:1,
     107             :                         sack_ok:1,
     108             :                         wscale_idx:3,
     109             :                         mss_idx:3;
     110             :         } flags;
     111             : };
     112             : 
     113             : #define PF_SYNCOOKIE_SECRET_SIZE        SIPHASH_KEY_LENGTH
     114             : #define PF_SYNCOOKIE_SECRET_LIFETIME    15 /* seconds */
     115             : 
     116             : static struct {
     117             :         struct timeout  keytimeout;
     118             :         volatile uint   oddeven;
     119             :         SIPHASH_KEY     key[2];
     120             :         uint32_t        hiwat;  /* absolute; # of states */
     121             :         uint32_t        lowat;
     122             : } pf_syncookie_status;
     123             : 
     124             : void            pf_syncookie_rotate(void *);
     125             : void            pf_syncookie_newkey(void);
     126             : uint32_t        pf_syncookie_mac(struct pf_pdesc *, union pf_syncookie,
     127             :                     uint32_t);
     128             : uint32_t        pf_syncookie_generate(struct pf_pdesc *, uint16_t);
     129             : 
     130             : void
     131           0 : pf_syncookies_init(void)
     132             : {
     133           0 :         timeout_set(&pf_syncookie_status.keytimeout,
     134             :             pf_syncookie_rotate, NULL);
     135           0 :         pf_syncookie_status.hiwat = PFSTATE_HIWAT * PF_SYNCOOKIES_HIWATPCT/100;
     136           0 :         pf_syncookie_status.lowat = PFSTATE_HIWAT * PF_SYNCOOKIES_LOWATPCT/100;
     137           0 :         pf_syncookies_setmode(PF_SYNCOOKIES_NEVER);
     138           0 : }
     139             : 
     140             : int
     141           0 : pf_syncookies_setmode(u_int8_t mode)
     142             : {
     143           0 :         if (mode > PF_SYNCOOKIES_MODE_MAX)
     144           0 :                 return (EINVAL);
     145             : 
     146           0 :         if (pf_status.syncookies_mode == mode)
     147           0 :                 return (0);
     148             : 
     149           0 :         pf_status.syncookies_mode = mode;
     150           0 :         if (pf_status.syncookies_mode == PF_SYNCOOKIES_ALWAYS) {
     151           0 :                 pf_syncookie_newkey();
     152           0 :                 pf_status.syncookies_active = 1;
     153           0 :         }
     154           0 :         return (0);
     155           0 : }
     156             : 
     157             : int
     158           0 : pf_syncookies_setwats(u_int32_t hiwat, u_int32_t lowat)
     159             : {
     160           0 :         if (lowat > hiwat)
     161           0 :                 return (EINVAL);
     162             : 
     163           0 :         pf_syncookie_status.hiwat = hiwat;
     164           0 :         pf_syncookie_status.lowat = lowat;
     165           0 :         return (0);
     166           0 : }
     167             : 
     168             : int
     169           0 : pf_syncookies_getwats(struct pfioc_synflwats *wats)
     170             : {
     171           0 :         wats->hiwat = pf_syncookie_status.hiwat;
     172           0 :         wats->lowat = pf_syncookie_status.lowat;
     173           0 :         return (0);
     174             : }
     175             : 
     176             : int
     177           0 : pf_synflood_check(struct pf_pdesc *pd)
     178             : {
     179           0 :         KASSERT (pd->proto == IPPROTO_TCP);
     180             : 
     181           0 :         if (pd->m && (pd->m->m_pkthdr.pf.tag & PF_TAG_SYNCOOKIE_RECREATED))
     182           0 :                 return (0);
     183             : 
     184           0 :         if (pf_status.syncookies_mode != PF_SYNCOOKIES_ADAPTIVE)
     185           0 :                 return (pf_status.syncookies_mode);
     186             : 
     187           0 :         if (!pf_status.syncookies_active &&
     188           0 :             pf_status.states_halfopen > pf_syncookie_status.hiwat) {
     189           0 :                 pf_syncookie_newkey();
     190           0 :                 pf_status.syncookies_active = 1;
     191           0 :                 DPFPRINTF(LOG_WARNING,
     192             :                     "synflood detected, enabling syncookies");
     193           0 :                 pf_status.lcounters[LCNT_SYNFLOODS]++;
     194           0 :         }
     195             : 
     196           0 :         return (pf_status.syncookies_active);
     197           0 : }
     198             : 
     199             : void
     200           0 : pf_syncookie_send(struct pf_pdesc *pd)
     201             : {
     202             :         uint16_t        mss;
     203             :         uint32_t        iss;
     204             : 
     205           0 :         mss = max(tcp_mssdflt, pf_get_mss(pd));
     206           0 :         iss = pf_syncookie_generate(pd, mss);
     207           0 :         pf_send_tcp(NULL, pd->af, pd->dst, pd->src, *pd->dport, *pd->sport,
     208           0 :             iss, ntohl(pd->hdr.tcp.th_seq) + 1, TH_SYN|TH_ACK, 0, mss,
     209           0 :             0, 1, 0, pd->rdomain);
     210           0 :         pf_status.syncookies_inflight[pf_syncookie_status.oddeven]++;
     211           0 :         pf_status.lcounters[LCNT_SYNCOOKIES_SENT]++;
     212           0 : }
     213             : 
     214             : uint8_t
     215           0 : pf_syncookie_validate(struct pf_pdesc *pd)
     216             : {
     217             :         uint32_t                 hash, ack, seq;
     218             :         union pf_syncookie       cookie;
     219             : 
     220           0 :         KASSERT(pd->proto == IPPROTO_TCP);
     221             : 
     222           0 :         seq = ntohl(pd->hdr.tcp.th_seq) - 1;
     223           0 :         ack = ntohl(pd->hdr.tcp.th_ack) - 1;
     224           0 :         cookie.cookie = (ack & 0xff) ^ (ack >> 24);
     225             : 
     226             :         /* we don't know oddeven before setting the cookie (union) */
     227           0 :         if (pf_status.syncookies_inflight[cookie.flags.oddeven] == 0)
     228           0 :                 return (0);
     229             : 
     230           0 :         hash = pf_syncookie_mac(pd, cookie, seq);
     231           0 :         if ((ack & ~0xff) != (hash & ~0xff))
     232           0 :                 return (0);
     233             : 
     234           0 :         pf_status.syncookies_inflight[cookie.flags.oddeven]--;
     235           0 :         pf_status.lcounters[LCNT_SYNCOOKIES_VALID]++;
     236           0 :         return (1);
     237           0 : }
     238             : 
     239             : /*
     240             :  * all following functions private
     241             :  */
     242             : void
     243           0 : pf_syncookie_rotate(void *arg)
     244             : {
     245             :         /* do we want to disable syncookies? */
     246           0 :         if (pf_status.syncookies_active &&
     247           0 :             ((pf_status.syncookies_mode == PF_SYNCOOKIES_ADAPTIVE &&
     248           0 :             pf_status.states_halfopen + pf_status.syncookies_inflight[0] +
     249           0 :             pf_status.syncookies_inflight[1] < pf_syncookie_status.lowat) ||
     250           0 :             pf_status.syncookies_mode == PF_SYNCOOKIES_NEVER)) {
     251           0 :                 pf_status.syncookies_active = 0;
     252           0 :                 DPFPRINTF(LOG_WARNING, "syncookies disabled");
     253             :         }
     254             : 
     255             :         /* nothing in flight any more? delete keys and return */
     256           0 :         if (!pf_status.syncookies_active &&
     257           0 :             pf_status.syncookies_inflight[0] == 0 &&
     258           0 :             pf_status.syncookies_inflight[1] == 0) {
     259           0 :                 memset(&pf_syncookie_status.key[0], 0,
     260             :                     PF_SYNCOOKIE_SECRET_SIZE);
     261           0 :                 memset(&pf_syncookie_status.key[1], 0,
     262             :                     PF_SYNCOOKIE_SECRET_SIZE);
     263           0 :                 return;
     264             :         }
     265             : 
     266             :         /* new key, including timeout */
     267           0 :         pf_syncookie_newkey();
     268           0 : }
     269             : 
     270             : void
     271           0 : pf_syncookie_newkey(void)
     272             : {
     273           0 :         pf_syncookie_status.oddeven = (pf_syncookie_status.oddeven + 1) & 0x1;
     274           0 :         pf_status.syncookies_inflight[pf_syncookie_status.oddeven] = 0;
     275           0 :         arc4random_buf(&pf_syncookie_status.key[pf_syncookie_status.oddeven],
     276             :             PF_SYNCOOKIE_SECRET_SIZE);
     277           0 :         timeout_add_sec(&pf_syncookie_status.keytimeout,
     278             :             PF_SYNCOOKIE_SECRET_LIFETIME);
     279           0 : }
     280             : 
     281             : /*
     282             :  * Distribution and probability of certain MSS values.  Those in between are
     283             :  * rounded down to the next lower one.
     284             :  * [An Analysis of TCP Maximum Segment Sizes, S. Alcock and R. Nelson, 2011]
     285             :  *   .2%  .3%   5%    7%    7%    20%   15%   45%
     286             :  */
     287             : static int pf_syncookie_msstab[] = 
     288             :     { 216, 536, 1200, 1360, 1400, 1440, 1452, 1460 };
     289             : 
     290             : /*
     291             :  * Distribution and probability of certain WSCALE values.
     292             :  * The absence of the WSCALE option is encoded with index zero.
     293             :  * [WSCALE values histograms, Allman, 2012]
     294             :  *                                  X 10 10 35  5  6 14 10%   by host
     295             :  *                                  X 11  4  5  5 18 49  3%   by connections
     296             :  */
     297             : static int pf_syncookie_wstab[] = { 0, 0, 1, 2, 4, 6, 7, 8 };
     298             : 
     299             : uint32_t
     300           0 : pf_syncookie_mac(struct pf_pdesc *pd, union pf_syncookie cookie, uint32_t seq)
     301             : {
     302           0 :         SIPHASH_CTX     ctx;
     303           0 :         uint32_t        siphash[2];
     304             : 
     305           0 :         KASSERT(pd->proto == IPPROTO_TCP);
     306             : 
     307           0 :         SipHash24_Init(&ctx, &pf_syncookie_status.key[cookie.flags.oddeven]);
     308             : 
     309           0 :         switch (pd->af) {
     310             :         case AF_INET:
     311           0 :                 SipHash24_Update(&ctx, pd->src, sizeof(pd->src->v4));
     312           0 :                 SipHash24_Update(&ctx, pd->dst, sizeof(pd->dst->v4));
     313           0 :                 break;
     314             :         case AF_INET6:
     315           0 :                 SipHash24_Update(&ctx, pd->src, sizeof(pd->src->v6));
     316           0 :                 SipHash24_Update(&ctx, pd->dst, sizeof(pd->dst->v6));
     317           0 :                 break;
     318             :         default:
     319           0 :                 panic("unknown address family");
     320             :         }
     321             : 
     322           0 :         SipHash24_Update(&ctx, pd->sport, sizeof(*pd->sport));
     323           0 :         SipHash24_Update(&ctx, pd->dport, sizeof(*pd->dport));
     324           0 :         SipHash24_Update(&ctx, &seq, sizeof(seq));
     325           0 :         SipHash24_Update(&ctx, &cookie, sizeof(cookie));
     326           0 :         SipHash24_Final((uint8_t *)&siphash, &ctx);
     327             : 
     328           0 :         return (siphash[0] ^ siphash[1]);
     329           0 : }
     330             : 
     331             : uint32_t
     332           0 : pf_syncookie_generate(struct pf_pdesc *pd, uint16_t mss)
     333             : {
     334             :         uint8_t                  i, wscale;
     335             :         uint32_t                 iss, hash;
     336             :         union pf_syncookie       cookie;
     337             : 
     338             :         cookie.cookie = 0;
     339             : 
     340             :         /* map MSS */
     341           0 :         for (i = nitems(pf_syncookie_msstab) - 1;
     342           0 :             pf_syncookie_msstab[i] > mss && i > 0; i--)
     343             :                 /* nada */;
     344           0 :         cookie.flags.mss_idx = i;
     345             : 
     346             :         /* map WSCALE */
     347           0 :         wscale = pf_get_wscale(pd);
     348           0 :         for (i = nitems(pf_syncookie_wstab) - 1;
     349           0 :             pf_syncookie_wstab[i] > wscale && i > 0; i--)
     350             :                 /* nada */;
     351           0 :         cookie.flags.wscale_idx = i;
     352             :         cookie.flags.sack_ok = 0;       /* XXX */
     353             : 
     354           0 :         cookie.flags.oddeven = pf_syncookie_status.oddeven;
     355           0 :         hash = pf_syncookie_mac(pd, cookie, ntohl(pd->hdr.tcp.th_seq));
     356             : 
     357             :         /*
     358             :          * Put the flags into the hash and XOR them to get better ISS number
     359             :          * variance.  This doesn't enhance the cryptographic strength and is
     360             :          * done to prevent the 8 cookie bits from showing up directly on the
     361             :          * wire.
     362             :          */
     363           0 :         iss = hash & ~0xff;
     364           0 :         iss |= cookie.cookie ^ (hash >> 24);
     365             : 
     366           0 :         return (iss);
     367             : }
     368             : 
     369             : struct mbuf *
     370           0 : pf_syncookie_recreate_syn(struct pf_pdesc *pd)
     371             : {
     372             :         uint8_t                  wscale;
     373             :         uint16_t                 mss;
     374             :         uint32_t                 ack, seq;
     375             :         union pf_syncookie       cookie;
     376             : 
     377           0 :         seq = ntohl(pd->hdr.tcp.th_seq) - 1;
     378           0 :         ack = ntohl(pd->hdr.tcp.th_ack) - 1;
     379           0 :         cookie.cookie = (ack & 0xff) ^ (ack >> 24);
     380             : 
     381           0 :         if (cookie.flags.mss_idx >= nitems(pf_syncookie_msstab) ||
     382           0 :             cookie.flags.wscale_idx >= nitems(pf_syncookie_wstab))
     383           0 :                 return (NULL);
     384             : 
     385           0 :         mss = pf_syncookie_msstab[cookie.flags.mss_idx];
     386           0 :         wscale = pf_syncookie_wstab[cookie.flags.wscale_idx];
     387             : 
     388           0 :         return (pf_build_tcp(NULL, pd->af, pd->src, pd->dst, *pd->sport,
     389           0 :             *pd->dport, seq, 0, TH_SYN, wscale, mss, pd->ttl, 0,
     390           0 :             PF_TAG_SYNCOOKIE_RECREATED, cookie.flags.sack_ok, pd->rdomain));
     391           0 : }

Generated by: LCOV version 1.13