LCOV - code coverage report
Current view: top level - lib - conntrack-tcp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 180 201 89.6 %
Date: 2016-09-14 01:02:56 Functions: 9 9 100.0 %
Branches: 126 166 75.9 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2001 Daniel Hartmeier
       3                 :            :  * Copyright (c) 2002 - 2008 Henning Brauer
       4                 :            :  * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org>
       5                 :            :  * Copyright (c) 2015, 2016 Nicira, Inc.
       6                 :            :  * All rights reserved.
       7                 :            :  *
       8                 :            :  * Redistribution and use in source and binary forms, with or without
       9                 :            :  * modification, are permitted provided that the following conditions
      10                 :            :  * are met:
      11                 :            :  *
      12                 :            :  *    - Redistributions of source code must retain the above copyright
      13                 :            :  *      notice, this list of conditions and the following disclaimer.
      14                 :            :  *    - Redistributions in binary form must reproduce the above
      15                 :            :  *      copyright notice, this list of conditions and the following
      16                 :            :  *      disclaimer in the documentation and/or other materials provided
      17                 :            :  *      with the distribution.
      18                 :            :  *
      19                 :            :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      20                 :            :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      21                 :            :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      22                 :            :  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      23                 :            :  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      24                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      25                 :            :  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      26                 :            :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
      27                 :            :  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      28                 :            :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
      29                 :            :  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      30                 :            :  * POSSIBILITY OF SUCH DAMAGE.
      31                 :            :  *
      32                 :            :  * Effort sponsored in part by the Defense Advanced Research Projects
      33                 :            :  * Agency (DARPA) and Air Force Research Laboratory, Air Force
      34                 :            :  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
      35                 :            :  *
      36                 :            :  *      $OpenBSD: pf.c,v 1.634 2009/02/27 12:37:45 henning Exp $
      37                 :            :  */
      38                 :            : 
      39                 :            : #include <config.h>
      40                 :            : 
      41                 :            : #include "conntrack-private.h"
      42                 :            : #include "ct-dpif.h"
      43                 :            : #include "dp-packet.h"
      44                 :            : #include "util.h"
      45                 :            : 
      46                 :            : struct tcp_peer {
      47                 :            :     enum ct_dpif_tcp_state state;
      48                 :            :     uint32_t               seqlo;          /* Max sequence number sent     */
      49                 :            :     uint32_t               seqhi;          /* Max the other end ACKd + win */
      50                 :            :     uint16_t               max_win;        /* largest window (pre scaling) */
      51                 :            :     uint8_t                wscale;         /* window scaling factor        */
      52                 :            : };
      53                 :            : 
      54                 :            : struct conn_tcp {
      55                 :            :     struct conn up;
      56                 :            :     struct tcp_peer peer[2];
      57                 :            : };
      58                 :            : 
      59                 :            : enum {
      60                 :            :     TCPOPT_EOL,
      61                 :            :     TCPOPT_NOP,
      62                 :            :     TCPOPT_WINDOW = 3,
      63                 :            : };
      64                 :            : 
      65                 :            : /* TCP sequence numbers are 32 bit integers operated
      66                 :            :  * on with modular arithmetic.  These macros can be
      67                 :            :  * used to compare such integers. */
      68                 :            : #define SEQ_LT(a,b)     INT_MOD_LT(a, b)
      69                 :            : #define SEQ_LEQ(a,b)    INT_MOD_LEQ(a, b)
      70                 :            : #define SEQ_GT(a,b)     INT_MOD_GT(a, b)
      71                 :            : #define SEQ_GEQ(a,b)    INT_MOD_GEQ(a, b)
      72                 :            : 
      73                 :            : #define SEQ_MIN(a, b)   INT_MOD_MIN(a, b)
      74                 :            : #define SEQ_MAX(a, b)   INT_MOD_MAX(a, b)
      75                 :            : 
      76                 :            : static struct conn_tcp*
      77                 :        492 : conn_tcp_cast(const struct conn* conn)
      78                 :            : {
      79                 :        492 :     return CONTAINER_OF(conn, struct conn_tcp, up);
      80                 :            : }
      81                 :            : 
      82                 :            : /* pf does this in in pf_normalize_tcp(), and it is called only if scrub
      83                 :            :  * is enabled.  We're not scrubbing, but this check seems reasonable.  */
      84                 :            : static bool
      85                 :        544 : tcp_invalid_flags(uint16_t flags)
      86                 :            : {
      87                 :            : 
      88         [ +  + ]:        544 :     if (flags & TCP_SYN) {
      89 [ +  - ][ -  + ]:        136 :         if (flags & TCP_RST || flags & TCP_FIN) {
      90                 :          0 :             return true;
      91                 :            :         }
      92                 :            :     } else {
      93                 :            :         /* Illegal packet */
      94         [ -  + ]:        408 :         if (!(flags & (TCP_ACK|TCP_RST))) {
      95                 :          0 :             return true;
      96                 :            :         }
      97                 :            :     }
      98                 :            : 
      99         [ +  + ]:        544 :     if (!(flags & TCP_ACK)) {
     100                 :            :         /* These flags are only valid if ACK is set */
     101 [ +  - ][ +  - ]:         82 :         if ((flags & TCP_FIN) || (flags & TCP_PSH) || (flags & TCP_URG)) {
                 [ -  + ]
     102                 :          0 :             return true;
     103                 :            :         }
     104                 :            :     }
     105                 :            : 
     106                 :        544 :     return false;
     107                 :            : }
     108                 :            : 
     109                 :            : #define TCP_MAX_WSCALE 14
     110                 :            : #define CT_WSCALE_FLAG 0x80
     111                 :            : #define CT_WSCALE_UNKNOWN 0x40
     112                 :            : #define CT_WSCALE_MASK 0xf
     113                 :            : 
     114                 :            : static uint8_t
     115                 :         86 : tcp_get_wscale(const struct tcp_header *tcp)
     116                 :            : {
     117                 :         86 :     int len = TCP_OFFSET(tcp->tcp_ctl) * 4 - sizeof *tcp;
     118                 :         86 :     const uint8_t *opt = (const uint8_t *)(tcp + 1);
     119                 :         86 :     uint8_t wscale = 0;
     120                 :            :     uint8_t optlen;
     121                 :            : 
     122         [ +  + ]:        508 :     while (len >= 3) {
     123   [ -  +  +  + ]:        422 :         switch (*opt) {
     124                 :            :         case TCPOPT_EOL:
     125                 :          0 :             return wscale;
     126                 :            :         case TCPOPT_NOP:
     127                 :         84 :             opt++;
     128                 :         84 :             len--;
     129                 :         84 :             break;
     130                 :            :         case TCPOPT_WINDOW:
     131                 :         84 :             wscale = MIN(opt[2], TCP_MAX_WSCALE);
     132                 :         84 :             wscale |= CT_WSCALE_FLAG;
     133                 :            :             /* fall through */
     134                 :            :         default:
     135                 :        338 :             optlen = opt[1];
     136         [ -  + ]:        338 :             if (optlen < 2) {
     137                 :          0 :                 optlen = 2;
     138                 :            :             }
     139                 :        338 :             len -= optlen;
     140                 :        338 :             opt += optlen;
     141                 :            :         }
     142                 :            :     }
     143                 :            : 
     144                 :         86 :     return wscale;
     145                 :            : }
     146                 :            : 
     147                 :            : static uint32_t
     148                 :        504 : tcp_payload_length(struct dp_packet *pkt)
     149                 :            : {
     150                 :       1008 :     return (char *) dp_packet_tail(pkt) - dp_packet_l2_pad_size(pkt)
     151                 :        504 :            - (char *) dp_packet_get_tcp_payload(pkt);
     152                 :            : }
     153                 :            : 
     154                 :            : static enum ct_update_res
     155                 :        446 : tcp_conn_update(struct conn *conn_, struct conntrack_bucket *ctb,
     156                 :            :                 struct dp_packet *pkt, bool reply, long long now)
     157                 :            : {
     158                 :        446 :     struct conn_tcp *conn = conn_tcp_cast(conn_);
     159                 :        446 :     struct tcp_header *tcp = dp_packet_l4(pkt);
     160                 :            :     /* The peer that sent 'pkt' */
     161                 :        446 :     struct tcp_peer *src = &conn->peer[reply ? 1 : 0];
     162                 :            :     /* The peer that should receive 'pkt' */
     163         [ +  + ]:        446 :     struct tcp_peer *dst = &conn->peer[reply ? 0 : 1];
     164                 :        446 :     uint8_t sws = 0, dws = 0;
     165                 :        446 :     uint16_t tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
     166                 :            : 
     167                 :        446 :     uint16_t win = ntohs(tcp->tcp_winsz);
     168                 :            :     uint32_t ack, end, seq, orig_seq;
     169                 :        446 :     uint32_t p_len = tcp_payload_length(pkt);
     170                 :            :     int ackskew;
     171                 :            : 
     172         [ -  + ]:        446 :     if (tcp_invalid_flags(tcp_flags)) {
     173                 :          0 :         return CT_UPDATE_INVALID;
     174                 :            :     }
     175                 :            : 
     176         [ +  + ]:        446 :     if (((tcp_flags & (TCP_SYN | TCP_ACK)) == TCP_SYN)
     177         [ +  + ]:          2 :         && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2
     178         [ +  - ]:          1 :         && src->state >= CT_DPIF_TCPS_FIN_WAIT_2) {
     179                 :          1 :         src->state = dst->state = CT_DPIF_TCPS_CLOSED;
     180                 :          1 :         return CT_UPDATE_NEW;
     181                 :            :     }
     182                 :            : 
     183         [ +  + ]:        445 :     if (src->wscale & CT_WSCALE_FLAG
     184         [ +  + ]:        366 :         && dst->wscale & CT_WSCALE_FLAG
     185         [ +  + ]:        345 :         && !(tcp_flags & TCP_SYN)) {
     186                 :            : 
     187                 :        327 :         sws = src->wscale & CT_WSCALE_MASK;
     188                 :        327 :         dws = dst->wscale & CT_WSCALE_MASK;
     189                 :            : 
     190         [ +  + ]:        118 :     } else if (src->wscale & CT_WSCALE_UNKNOWN
     191         [ +  - ]:         10 :                && dst->wscale & CT_WSCALE_UNKNOWN
     192         [ +  - ]:         10 :                && !(tcp_flags & TCP_SYN)) {
     193                 :            : 
     194                 :         10 :         sws = TCP_MAX_WSCALE;
     195                 :         10 :         dws = TCP_MAX_WSCALE;
     196                 :            :     }
     197                 :            : 
     198                 :            :     /*
     199                 :            :      * Sequence tracking algorithm from Guido van Rooij's paper:
     200                 :            :      *   http://www.madison-gurkha.com/publications/tcp_filtering/
     201                 :            :      *      tcp_filtering.ps
     202                 :            :      */
     203                 :            : 
     204                 :        445 :     orig_seq = seq = ntohl(get_16aligned_be32(&tcp->tcp_seq));
     205         [ +  + ]:        445 :     if (src->state < CT_DPIF_TCPS_SYN_SENT) {
     206                 :            :         /* First packet from this end. Set its state */
     207                 :            : 
     208                 :         55 :         ack = ntohl(get_16aligned_be32(&tcp->tcp_ack));
     209                 :            : 
     210                 :         55 :         end = seq + p_len;
     211         [ +  + ]:         55 :         if (tcp_flags & TCP_SYN) {
     212                 :         31 :             end++;
     213         [ +  + ]:         31 :             if (dst->wscale & CT_WSCALE_FLAG) {
     214                 :         29 :                 src->wscale = tcp_get_wscale(tcp);
     215         [ +  - ]:         29 :                 if (src->wscale & CT_WSCALE_FLAG) {
     216                 :            :                     /* Remove scale factor from initial window */
     217                 :         29 :                     sws = src->wscale & CT_WSCALE_MASK;
     218                 :         29 :                     win = DIV_ROUND_UP((uint32_t) win, 1 << sws);
     219                 :         29 :                     dws = dst->wscale & CT_WSCALE_MASK;
     220                 :            :                 } else {
     221                 :            :                     /* fixup other window */
     222                 :          0 :                     dst->max_win <<= dst->wscale & CT_WSCALE_MASK;
     223                 :            :                     /* in case of a retrans SYN|ACK */
     224                 :          0 :                     dst->wscale = 0;
     225                 :            :                 }
     226                 :            :             }
     227                 :            :         }
     228         [ -  + ]:         55 :         if (tcp_flags & TCP_FIN) {
     229                 :          0 :             end++;
     230                 :            :         }
     231                 :            : 
     232                 :         55 :         src->seqlo = seq;
     233                 :         55 :         src->state = CT_DPIF_TCPS_SYN_SENT;
     234                 :            :         /*
     235                 :            :          * May need to slide the window (seqhi may have been set by
     236                 :            :          * the crappy stack check or if we picked up the connection
     237                 :            :          * after establishment)
     238                 :            :          */
     239         [ -  + ]:         55 :         if (src->seqhi == 1
     240         [ #  # ]:          0 :                 || SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi)) {
     241                 :         55 :             src->seqhi = end + MAX(1, dst->max_win << dws);
     242                 :            :         }
     243         [ +  + ]:         55 :         if (win > src->max_win) {
     244                 :         55 :             src->max_win = win;
     245                 :            :         }
     246                 :            : 
     247                 :            :     } else {
     248                 :        390 :         ack = ntohl(get_16aligned_be32(&tcp->tcp_ack));
     249                 :        390 :         end = seq + p_len;
     250         [ +  + ]:        390 :         if (tcp_flags & TCP_SYN) {
     251                 :         18 :             end++;
     252                 :            :         }
     253         [ +  + ]:        390 :         if (tcp_flags & TCP_FIN) {
     254                 :         49 :             end++;
     255                 :            :         }
     256                 :            :     }
     257                 :            : 
     258         [ +  + ]:        445 :     if ((tcp_flags & TCP_ACK) == 0) {
     259                 :            :         /* Let it pass through the ack skew check */
     260                 :          1 :         ack = dst->seqlo;
     261         [ -  + ]:        444 :     } else if ((ack == 0
     262         [ #  # ]:          0 :                 && (tcp_flags & (TCP_ACK|TCP_RST)) == (TCP_ACK|TCP_RST))
     263                 :            :                /* broken tcp stacks do not set ack */) {
     264                 :            :         /* Many stacks (ours included) will set the ACK number in an
     265                 :            :          * FIN|ACK if the SYN times out -- no sequence to ACK. */
     266                 :          0 :         ack = dst->seqlo;
     267                 :            :     }
     268                 :            : 
     269         [ +  + ]:        445 :     if (seq == end) {
     270                 :            :         /* Ease sequencing restrictions on no data packets */
     271                 :        220 :         seq = src->seqlo;
     272                 :        220 :         end = seq;
     273                 :            :     }
     274                 :            : 
     275                 :        445 :     ackskew = dst->seqlo - ack;
     276                 :            : #define MAXACKWINDOW (0xffff + 1500)    /* 1500 is an arbitrary fudge factor */
     277         [ +  + ]:        445 :     if (SEQ_GEQ(src->seqhi, end)
     278                 :            :         /* Last octet inside other's window space */
     279         [ +  - ]:        426 :         && SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))
     280                 :            :         /* Retrans: not more than one window back */
     281         [ +  + ]:        426 :         && (ackskew >= -MAXACKWINDOW)
     282                 :            :         /* Acking not more than one reassembled fragment backwards */
     283         [ +  + ]:        425 :         && (ackskew <= (MAXACKWINDOW << sws))
     284                 :            :         /* Acking not more than one window forward */
     285 [ +  + ][ -  + ]:        423 :         && ((tcp_flags & TCP_RST) == 0 || orig_seq == src->seqlo
     286 [ #  # ][ #  # ]:          0 :             || (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo))) {
     287                 :            :         /* Require an exact/+1 sequence match on resets when possible */
     288                 :            : 
     289                 :            :         /* update max window */
     290         [ +  + ]:        423 :         if (src->max_win < win) {
     291                 :         49 :             src->max_win = win;
     292                 :            :         }
     293                 :            :         /* synchronize sequencing */
     294         [ +  + ]:        423 :         if (SEQ_GT(end, src->seqlo)) {
     295                 :        191 :             src->seqlo = end;
     296                 :            :         }
     297                 :            :         /* slide the window of what the other end can send */
     298         [ +  + ]:        423 :         if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) {
     299                 :        381 :             dst->seqhi = ack + MAX((win << sws), 1);
     300                 :            :         }
     301                 :            : 
     302                 :            :         /* update states */
     303 [ +  + ][ -  + ]:        423 :         if (tcp_flags & TCP_SYN && src->state < CT_DPIF_TCPS_SYN_SENT) {
     304                 :          0 :                 src->state = CT_DPIF_TCPS_SYN_SENT;
     305                 :            :         }
     306 [ +  + ][ +  + ]:        423 :         if (tcp_flags & TCP_FIN && src->state < CT_DPIF_TCPS_CLOSING) {
     307                 :         44 :                 src->state = CT_DPIF_TCPS_CLOSING;
     308                 :            :         }
     309         [ +  + ]:        423 :         if (tcp_flags & TCP_ACK) {
     310         [ +  + ]:        422 :             if (dst->state == CT_DPIF_TCPS_SYN_SENT) {
     311                 :         77 :                 dst->state = CT_DPIF_TCPS_ESTABLISHED;
     312         [ +  + ]:        345 :             } else if (dst->state == CT_DPIF_TCPS_CLOSING) {
     313                 :         44 :                 dst->state = CT_DPIF_TCPS_FIN_WAIT_2;
     314                 :            :             }
     315                 :            :         }
     316         [ +  + ]:        423 :         if (tcp_flags & TCP_RST) {
     317                 :         24 :             src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT;
     318                 :            :         }
     319                 :            : 
     320         [ +  + ]:        846 :         if (src->state >= CT_DPIF_TCPS_FIN_WAIT_2
     321         [ +  - ]:         47 :             && dst->state >= CT_DPIF_TCPS_FIN_WAIT_2) {
     322                 :         47 :             conn_update_expiration(ctb, &conn->up, CT_TM_TCP_CLOSED, now);
     323         [ +  + ]:        376 :         } else if (src->state >= CT_DPIF_TCPS_CLOSING
     324         [ +  + ]:         47 :                    && dst->state >= CT_DPIF_TCPS_CLOSING) {
     325                 :         24 :             conn_update_expiration(ctb, &conn->up, CT_TM_TCP_FIN_WAIT, now);
     326         [ +  + ]:        352 :         } else if (src->state < CT_DPIF_TCPS_ESTABLISHED
     327         [ +  + ]:        303 :                    || dst->state < CT_DPIF_TCPS_ESTABLISHED) {
     328                 :         50 :             conn_update_expiration(ctb, &conn->up, CT_TM_TCP_OPENING, now);
     329         [ +  + ]:        302 :         } else if (src->state >= CT_DPIF_TCPS_CLOSING
     330         [ +  + ]:        279 :                    || dst->state >= CT_DPIF_TCPS_CLOSING) {
     331                 :         37 :             conn_update_expiration(ctb, &conn->up, CT_TM_TCP_CLOSING, now);
     332                 :            :         } else {
     333                 :        265 :             conn_update_expiration(ctb, &conn->up, CT_TM_TCP_ESTABLISHED, now);
     334                 :            :         }
     335         [ -  + ]:         22 :     } else if ((dst->state < CT_DPIF_TCPS_SYN_SENT
     336         [ #  # ]:          0 :                 || dst->state >= CT_DPIF_TCPS_FIN_WAIT_2
     337         [ #  # ]:          0 :                 || src->state >= CT_DPIF_TCPS_FIN_WAIT_2)
     338         [ +  - ]:         22 :                && SEQ_GEQ(src->seqhi + MAXACKWINDOW, end)
     339                 :            :                /* Within a window forward of the originating packet */
     340         [ +  - ]:         22 :                && SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
     341                 :            :                /* Within a window backward of the originating packet */
     342                 :            : 
     343                 :            :         /*
     344                 :            :          * This currently handles three situations:
     345                 :            :          *  1) Stupid stacks will shotgun SYNs before their peer
     346                 :            :          *     replies.
     347                 :            :          *  2) When PF catches an already established stream (the
     348                 :            :          *     firewall rebooted, the state table was flushed, routes
     349                 :            :          *     changed...)
     350                 :            :          *  3) Packets get funky immediately after the connection
     351                 :            :          *     closes (this should catch Solaris spurious ACK|FINs
     352                 :            :          *     that web servers like to spew after a close)
     353                 :            :          *
     354                 :            :          * This must be a little more careful than the above code
     355                 :            :          * since packet floods will also be caught here. We don't
     356                 :            :          * update the TTL here to mitigate the damage of a packet
     357                 :            :          * flood and so the same code can handle awkward establishment
     358                 :            :          * and a loosened connection close.
     359                 :            :          * In the establishment case, a correct peer response will
     360                 :            :          * validate the connection, go through the normal state code
     361                 :            :          * and keep updating the state TTL.
     362                 :            :          */
     363                 :            : 
     364                 :            :         /* update max window */
     365         [ +  + ]:         22 :         if (src->max_win < win) {
     366                 :          2 :             src->max_win = win;
     367                 :            :         }
     368                 :            :         /* synchronize sequencing */
     369         [ +  + ]:         22 :         if (SEQ_GT(end, src->seqlo)) {
     370                 :          5 :             src->seqlo = end;
     371                 :            :         }
     372                 :            :         /* slide the window of what the other end can send */
     373         [ +  + ]:         22 :         if (SEQ_GEQ(ack + (win << sws), dst->seqhi)) {
     374                 :         10 :             dst->seqhi = ack + MAX((win << sws), 1);
     375                 :            :         }
     376                 :            : 
     377                 :            :         /*
     378                 :            :          * Cannot set dst->seqhi here since this could be a shotgunned
     379                 :            :          * SYN and not an already established connection.
     380                 :            :          */
     381                 :            : 
     382 [ +  + ][ +  - ]:         22 :         if (tcp_flags & TCP_FIN && src->state < CT_DPIF_TCPS_CLOSING) {
     383                 :          2 :             src->state = CT_DPIF_TCPS_CLOSING;
     384                 :            :         }
     385                 :            : 
     386         [ -  + ]:         22 :         if (tcp_flags & TCP_RST) {
     387                 :          0 :             src->state = dst->state = CT_DPIF_TCPS_TIME_WAIT;
     388                 :            :         }
     389                 :            :     } else {
     390                 :          0 :         return CT_UPDATE_INVALID;
     391                 :            :     }
     392                 :            : 
     393                 :        445 :     return CT_UPDATE_VALID;
     394                 :            : }
     395                 :            : 
     396                 :            : static bool
     397                 :         98 : tcp_valid_new(struct dp_packet *pkt)
     398                 :            : {
     399                 :         98 :     struct tcp_header *tcp = dp_packet_l4(pkt);
     400                 :         98 :     uint16_t tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
     401                 :            : 
     402         [ -  + ]:         98 :     if (tcp_invalid_flags(tcp_flags)) {
     403                 :          0 :         return false;
     404                 :            :     }
     405                 :            : 
     406                 :            :     /* A syn+ack is not allowed to create a connection.  We want to allow
     407                 :            :      * totally new connections (syn) or already established, not partially
     408                 :            :      * open (syn+ack). */
     409 [ +  + ][ +  + ]:         98 :     if ((tcp_flags & TCP_SYN) && (tcp_flags & TCP_ACK)) {
     410                 :          6 :         return false;
     411                 :            :     }
     412                 :            : 
     413                 :         92 :     return true;
     414                 :            : }
     415                 :            : 
     416                 :            : static struct conn *
     417                 :         58 : tcp_new_conn(struct conntrack_bucket *ctb, struct dp_packet *pkt,
     418                 :            :              long long now)
     419                 :            : {
     420                 :         58 :     struct conn_tcp* newconn = NULL;
     421                 :         58 :     struct tcp_header *tcp = dp_packet_l4(pkt);
     422                 :            :     struct tcp_peer *src, *dst;
     423                 :         58 :     uint16_t tcp_flags = TCP_FLAGS(tcp->tcp_ctl);
     424                 :            : 
     425                 :         58 :     newconn = xzalloc(sizeof *newconn);
     426                 :            : 
     427                 :         58 :     src = &newconn->peer[0];
     428                 :         58 :     dst = &newconn->peer[1];
     429                 :            : 
     430                 :         58 :     src->seqlo = ntohl(get_16aligned_be32(&tcp->tcp_seq));
     431                 :         58 :     src->seqhi = src->seqlo + tcp_payload_length(pkt) + 1;
     432                 :            : 
     433         [ +  + ]:         58 :     if (tcp_flags & TCP_SYN) {
     434                 :         57 :         src->seqhi++;
     435                 :         57 :         src->wscale = tcp_get_wscale(tcp);
     436                 :            :     } else {
     437                 :          1 :         src->wscale = CT_WSCALE_UNKNOWN;
     438                 :          1 :         dst->wscale = CT_WSCALE_UNKNOWN;
     439                 :            :     }
     440                 :         58 :     src->max_win = MAX(ntohs(tcp->tcp_winsz), 1);
     441         [ +  + ]:         58 :     if (src->wscale & CT_WSCALE_MASK) {
     442                 :            :         /* Remove scale factor from initial window */
     443                 :         55 :         uint8_t sws = src->wscale & CT_WSCALE_MASK;
     444                 :         55 :         src->max_win = DIV_ROUND_UP((uint32_t) src->max_win, 1 << sws);
     445                 :            :     }
     446         [ -  + ]:         58 :     if (tcp_flags & TCP_FIN) {
     447                 :          0 :         src->seqhi++;
     448                 :            :     }
     449                 :         58 :     dst->seqhi = 1;
     450                 :         58 :     dst->max_win = 1;
     451                 :         58 :     src->state = CT_DPIF_TCPS_SYN_SENT;
     452                 :         58 :     dst->state = CT_DPIF_TCPS_CLOSED;
     453                 :            : 
     454                 :         58 :     conn_init_expiration(ctb, &newconn->up, CT_TM_TCP_FIRST_PACKET,
     455                 :            :                          now);
     456                 :            : 
     457                 :         58 :     return &newconn->up;
     458                 :            : }
     459                 :            : 
     460                 :            : static uint8_t
     461                 :         92 : tcp_peer_to_protoinfo_flags(const struct tcp_peer *peer)
     462                 :            : {
     463                 :         92 :     uint8_t res = 0;
     464                 :            : 
     465         [ +  + ]:         92 :     if (peer->wscale & CT_WSCALE_FLAG) {
     466                 :         70 :         res |= CT_DPIF_TCPF_WINDOW_SCALE;
     467                 :            :     }
     468                 :            : 
     469         [ -  + ]:         92 :     if (peer->wscale & CT_WSCALE_UNKNOWN) {
     470                 :          0 :         res |= CT_DPIF_TCPF_BE_LIBERAL;
     471                 :            :     }
     472                 :            : 
     473                 :         92 :     return res;
     474                 :            : }
     475                 :            : 
     476                 :            : static void
     477                 :         46 : tcp_conn_get_protoinfo(const struct conn *conn_,
     478                 :            :                        struct ct_dpif_protoinfo *protoinfo)
     479                 :            : {
     480                 :         46 :     const struct conn_tcp *conn = conn_tcp_cast(conn_);
     481                 :            : 
     482                 :         46 :     protoinfo->proto = IPPROTO_TCP;
     483                 :         46 :     protoinfo->tcp.state_orig = conn->peer[0].state;
     484                 :         46 :     protoinfo->tcp.state_reply = conn->peer[1].state;
     485                 :            : 
     486                 :         46 :     protoinfo->tcp.wscale_orig = conn->peer[0].wscale & CT_WSCALE_MASK;
     487                 :         46 :     protoinfo->tcp.wscale_reply = conn->peer[1].wscale & CT_WSCALE_MASK;
     488                 :            : 
     489                 :         46 :     protoinfo->tcp.flags_orig = tcp_peer_to_protoinfo_flags(&conn->peer[0]);
     490                 :         46 :     protoinfo->tcp.flags_reply = tcp_peer_to_protoinfo_flags(&conn->peer[1]);
     491                 :         46 : }
     492                 :            : 
     493                 :            : struct ct_l4_proto ct_proto_tcp = {
     494                 :            :     .new_conn = tcp_new_conn,
     495                 :            :     .valid_new = tcp_valid_new,
     496                 :            :     .conn_update = tcp_conn_update,
     497                 :            :     .conn_get_protoinfo = tcp_conn_get_protoinfo,
     498                 :            : };

Generated by: LCOV version 1.12