LCOV - code coverage report
Current view: top level - src - ContentLine.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 110 162 67.9 %
Date: 2010-12-13 Functions: 12 21 57.1 %
Branches: 60 126 47.6 %

           Branch data     Line data    Source code
       1                 :            : // $Id: ContentLine.cc,v 1.1.2.8 2006/06/01 01:55:42 sommer Exp $
       2                 :            : 
       3                 :            : #include "ContentLine.h"
       4                 :            : #include "TCP.h"
       5                 :            : 
       6                 :       1386 : ContentLine_Analyzer::ContentLine_Analyzer(Connection* conn, bool orig)
       7                 :       1386 : : TCP_SupportAnalyzer(AnalyzerTag::ContentLine, conn, orig)
       8                 :            :         {
       9                 :       1386 :         InitState();
      10                 :       1386 :         }
      11                 :            : 
      12                 :            : ContentLine_Analyzer::ContentLine_Analyzer(AnalyzerTag::Tag tag,
      13                 :          0 :                                                 Connection* conn, bool orig)
      14                 :          0 : : TCP_SupportAnalyzer(tag, conn, orig)
      15                 :            :         {
      16                 :          0 :         InitState();
      17                 :          0 :         }
      18                 :            : 
      19                 :       1386 : void ContentLine_Analyzer::InitState()
      20                 :            :         {
      21                 :       1386 :         flag_NULs = 0;
      22                 :       1386 :         CR_LF_as_EOL = (CR_as_EOL | LF_as_EOL);
      23                 :       1386 :         skip_deliveries = 0;
      24                 :       1386 :         skip_partial = 0;
      25                 :       1386 :         buf = 0;
      26                 :       1386 :         seq_delivered_in_lines = 0;
      27                 :       1386 :         skip_pending = 0;
      28                 :       1386 :         seq = 0;
      29                 :       1386 :         seq_to_skip = 0;
      30                 :       1386 :         plain_delivery_length = 0;
      31                 :       1386 :         is_plain = 0;
      32                 :            : 
      33                 :       1386 :         InitBuffer(0);
      34                 :       1386 :         }
      35                 :            : 
      36                 :       1386 : void ContentLine_Analyzer::InitBuffer(int size)
      37                 :            :         {
      38 [ -  + ][ #  # ]:       1386 :         if ( buf && buf_len >= size )
      39                 :            :                 // Don't shrink the buffer, because it's not clear in that
      40                 :            :                 // case how to deal with characters in it that no longer fit.
      41                 :          0 :                 return;
      42                 :            : 
      43         [ +  - ]:       1386 :         if ( size < 128 )
      44                 :       1386 :                 size = 128;
      45                 :            : 
      46                 :       1386 :         u_char* b = new u_char[size];
      47                 :            : 
      48         [ -  + ]:       1386 :         if ( buf )
      49                 :            :                 {
      50         [ #  # ]:          0 :                 if ( offset > 0 )
      51                 :          0 :                         memcpy(b, buf, offset);
      52         [ #  # ]:          0 :                 delete [] buf;
      53                 :            :                 }
      54                 :            :         else
      55                 :            :                 {
      56                 :       1386 :                 offset = 0;
      57                 :       1386 :                 last_char = 0;
      58                 :            :                 }
      59                 :            : 
      60                 :       1386 :         buf = b;
      61                 :       1386 :         buf_len = size;
      62                 :            :         }
      63                 :            : 
      64                 :       1386 : ContentLine_Analyzer::~ContentLine_Analyzer()
      65                 :            :         {
      66 [ +  - ][ #  # ]:       1386 :         delete [] buf;
                 [ #  # ]
      67 [ +  - ][ #  # ]:       1386 :         }
                 [ #  # ]
      68                 :            : 
      69                 :          0 : int ContentLine_Analyzer::HasPartialLine() const
      70                 :            :         {
      71 [ #  # ][ #  # ]:          0 :         return buf && offset > 0;
      72                 :            :         }
      73                 :            : 
      74                 :            : void ContentLine_Analyzer::DeliverStream(int len, const u_char* data,
      75                 :       5789 :                                                 bool is_orig)
      76                 :            :         {
      77                 :       5789 :         TCP_SupportAnalyzer::DeliverStream(len, data, is_orig);
      78                 :            : 
      79   [ +  -  +  + ]:       5789 :         if ( len <= 0 || SkipDeliveries() )
                 [ +  + ]
      80                 :       1580 :                 return;
      81                 :            : 
      82         [ +  + ]:       4209 :         if ( skip_partial )
      83                 :            :                 {
      84                 :            :                 TCP_Analyzer* tcp =
      85                 :       3380 :                         static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
      86                 :            : 
      87   [ +  -  +  + ]:       3380 :                 if ( tcp && tcp->IsPartial() )
                 [ +  + ]
      88                 :       1191 :                         return;
      89                 :            :                 }
      90                 :            : 
      91 [ +  - ][ +  + ]:       3018 :         if ( buf && len + offset >= buf_len )
      92                 :            :                 { // Make sure we have enough room to accommodate the new stuff.
      93                 :        743 :                 int old_buf_len = buf_len;
      94                 :        743 :                 buf_len = ((offset + len) * 3) / 2 + 1;
      95                 :            : 
      96                 :        743 :                 u_char* tmp = new u_char[buf_len];
      97         [ +  + ]:     169949 :                 for ( int i = 0; i < old_buf_len; ++i )
      98                 :     169206 :                         tmp[i] = buf[i];
      99                 :            : 
     100         [ +  - ]:        743 :                 delete [] buf;
     101                 :        743 :                 buf = tmp;
     102                 :            : 
     103         [ -  + ]:        743 :                 if ( ! buf )
     104                 :          0 :                         internal_error("out of memory delivering endpoint line");
     105                 :            :                 }
     106                 :            : 
     107                 :       3018 :         DoDeliver(len, data);
     108                 :            : 
     109                 :       5789 :         seq += len;
     110                 :            :         }
     111                 :            : 
     112                 :        338 : void ContentLine_Analyzer::Undelivered(int seq, int len, bool orig)
     113                 :            :         {
     114                 :        338 :         ForwardUndelivered(seq, len, orig);
     115                 :        338 :         }
     116                 :            : 
     117                 :        717 : void ContentLine_Analyzer::EndpointEOF(bool is_orig)
     118                 :            :         {
     119         [ +  + ]:        717 :         if ( offset > 0 )
     120                 :          8 :                 DeliverStream(1, (const u_char*) "\n", is_orig);
     121                 :        717 :         }
     122                 :            : 
     123                 :        927 : void ContentLine_Analyzer::SetPlainDelivery(int length)
     124                 :            :         {
     125         [ -  + ]:        927 :         if ( length < 0 )
     126                 :          0 :                 internal_error("negative length for plain delivery");
     127                 :            : 
     128                 :        927 :         plain_delivery_length = length;
     129                 :        927 :         }
     130                 :            : 
     131                 :       3018 : void ContentLine_Analyzer::DoDeliver(int len, const u_char* data)
     132                 :            :         {
     133                 :       3018 :         seq_delivered_in_lines = seq;
     134                 :            : 
     135 [ +  + ][ +  - ]:      17558 :         while ( len > 0 && ! SkipDeliveries() )
                 [ +  + ]
     136                 :            :                 {
     137 [ +  - ][ +  + ]:      14540 :                 if ( (CR_LF_as_EOL & CR_as_EOL) &&
                 [ +  - ]
     138                 :            :                      last_char == '\r' && *data == '\n' )
     139                 :            :                         {
     140                 :            :                         // CR is already considered as EOL.
     141                 :            :                         // Compress CRLF to just one line termination.
     142                 :            :                         //
     143                 :            :                         // Note, we test this prior to checking for
     144                 :            :                         // "plain delivery" because (1) we might have
     145                 :            :                         // made the decision to switch to plain delivery
     146                 :            :                         // based on a line terminated with '\r' for
     147                 :            :                         // which a '\n' then arrived, and (2) we are
     148                 :            :                         // careful when executing plain delivery to
     149                 :            :                         // clear last_char once we do so.
     150                 :          2 :                         last_char = *data;
     151                 :          2 :                         --len; ++data; ++seq;
     152                 :          2 :                         ++seq_delivered_in_lines;
     153                 :            :                         }
     154                 :            : 
     155         [ +  + ]:      14540 :                 if ( plain_delivery_length > 0 )
     156                 :            :                         {
     157                 :       2121 :                         int deliver_plain = min(plain_delivery_length, len);
     158                 :            : 
     159                 :       2121 :                         last_char = 0; // clear last_char
     160                 :       2121 :                         plain_delivery_length -= deliver_plain;
     161                 :       2121 :                         is_plain = 1;
     162                 :            : 
     163                 :       2121 :                         ForwardStream(deliver_plain, data, IsOrig());
     164                 :            : 
     165                 :       2121 :                         is_plain = 0;
     166                 :            : 
     167                 :       2121 :                         data += deliver_plain;
     168                 :       2121 :                         len -= deliver_plain;
     169         [ +  + ]:       2121 :                         if ( len == 0 )
     170                 :       2023 :                                 return;
     171                 :            :                         }
     172                 :            : 
     173         [ -  + ]:      12517 :                 if ( skip_pending > 0 )
     174                 :          0 :                         SkipBytes(skip_pending);
     175                 :            : 
     176                 :            :                 // Note that the skipping must take place *after*
     177                 :            :                 // the CR/LF check above, so that the '\n' of the
     178                 :            :                 // previous line is skipped first.
     179         [ -  + ]:      12517 :                 if ( seq < seq_to_skip )
     180                 :            :                         {
     181                 :            :                         // Skip rest of the data and return
     182                 :          0 :                         int skip_len = seq_to_skip - seq;
     183         [ #  # ]:          0 :                         if ( skip_len > len )
     184                 :          0 :                                 skip_len = len;
     185                 :            : 
     186                 :          0 :                         ForwardUndelivered(seq, skip_len, IsOrig());
     187                 :            : 
     188                 :          0 :                         len -= skip_len; data += skip_len; seq += skip_len;
     189                 :          0 :                         seq_delivered_in_lines += skip_len;
     190                 :            :                         }
     191                 :            : 
     192         [ +  + ]:      12517 :                 if ( len <= 0 )
     193                 :          1 :                         break;
     194                 :            : 
     195                 :      12516 :                 int n = DoDeliverOnce(len, data);
     196                 :      12516 :                 len -= n;
     197                 :      12516 :                 data += n;
     198                 :      12516 :                 seq += n;
     199                 :            :                 }
     200                 :            :         }
     201                 :            : 
     202                 :      12516 : int ContentLine_Analyzer::DoDeliverOnce(int len, const u_char* data)
     203                 :            :         {
     204                 :      12516 :         const u_char* data_start = data;
     205                 :            : 
     206         [ -  + ]:      12516 :         if ( len <= 0 )
     207                 :          0 :                 return 0;
     208                 :            : 
     209         [ +  + ]:     694064 :         for ( ; len > 0; --len, ++data )
     210                 :            :                 {
     211         [ -  + ]:     693881 :                 if ( offset >= buf_len )
     212                 :          0 :                         InitBuffer(buf_len * 2);
     213                 :            : 
     214                 :     693881 :                 int c = data[0];
     215                 :            : 
     216                 :            : #define EMIT_LINE \
     217                 :            :         { \
     218                 :            :         buf[offset] = '\0'; \
     219                 :            :         int seq_len = data + 1 - data_start; \
     220                 :            :         seq_delivered_in_lines = seq + seq_len; \
     221                 :            :         last_char = c; \
     222                 :            :         ForwardStream(offset, buf, IsOrig()); \
     223                 :            :         offset = 0; \
     224                 :            :         return seq_len; \
     225                 :            :         }
     226                 :            : 
     227   [ +  +  -  + ]:     693881 :                 switch ( c ) {
     228                 :            :                 case '\r':
     229                 :            :                         // Look ahead for '\n'.
     230 [ +  + ][ +  - ]:      12332 :                         if ( len > 1 && data[1] == '\n' )
     231                 :            :                                 {
     232                 :      12330 :                                 --len; ++data;
     233                 :      12330 :                                 last_char = c;
     234                 :      12330 :                                 c = data[0];
     235                 :      12330 :                                 EMIT_LINE
     236                 :            :                                 }
     237                 :            : 
     238         [ +  - ]:          2 :                         else if ( CR_LF_as_EOL & CR_as_EOL )
     239                 :          2 :                                 EMIT_LINE
     240                 :            : 
     241                 :            :                         else
     242                 :          0 :                                 buf[offset++] = c;
     243                 :          0 :                         break;
     244                 :            : 
     245                 :            :                 case '\n':
     246         [ -  + ]:          1 :                         if ( last_char == '\r' )
     247                 :            :                                 {
     248                 :          0 :                                 --offset; // remove '\r'
     249                 :          0 :                                 EMIT_LINE
     250                 :            :                                 }
     251                 :            : 
     252         [ +  - ]:          1 :                         else if ( CR_LF_as_EOL & LF_as_EOL )
     253                 :          1 :                                 EMIT_LINE
     254                 :            : 
     255                 :            :                         else
     256                 :            :                                 {
     257         [ #  # ]:          0 :                                 if ( Conn()->FlagEvent(SINGULAR_LF) )
     258                 :          0 :                                         Conn()->Weird("line_terminated_with_single_LF");
     259                 :          0 :                                 buf[offset++] = c;
     260                 :            :                                 }
     261                 :          0 :                         break;
     262                 :            : 
     263                 :            :                 case '\0':
     264         [ #  # ]:          0 :                         if ( flag_NULs )
     265                 :          0 :                                 CheckNUL();
     266                 :            :                         else
     267                 :          0 :                                 buf[offset++] = c;
     268                 :          0 :                         break;
     269                 :            : 
     270                 :            :                 default:
     271                 :     681548 :                         buf[offset++] = c;
     272                 :            :                         break;
     273                 :            :                 }
     274                 :            : 
     275         [ -  + ]:     681548 :                 if ( last_char == '\r' )
     276         [ #  # ]:          0 :                         if ( Conn()->FlagEvent(SINGULAR_CR) )
     277                 :          0 :                                 Conn()->Weird("line_terminated_with_single_CR");
     278                 :            : 
     279                 :     681548 :                 last_char = c;
     280                 :            :                 }
     281                 :            : 
     282                 :      12516 :         return data - data_start;
     283                 :            :         }
     284                 :            : 
     285                 :          0 : void ContentLine_Analyzer::CheckNUL()
     286                 :            :         {
     287                 :            :         // If this is the first byte seen on this connection,
     288                 :            :         // and if the connection's state is PARTIAL, then we've
     289                 :            :         // intercepted a keep-alive, and shouldn't complain
     290                 :            :         // about it.  Note that for PARTIAL connections, the
     291                 :            :         // starting sequence number is adjusted as though there
     292                 :            :         // had been an initial SYN, so we check for whether
     293                 :            :         // the connection has at most two bytes so far.
     294                 :            : 
     295                 :            :         TCP_Analyzer* tcp =
     296                 :          0 :                 static_cast<TCP_ApplicationAnalyzer*>(Parent())->TCP();
     297                 :            : 
     298         [ #  # ]:          0 :         if ( tcp )
     299                 :            :                 {
     300         [ #  # ]:          0 :                 TCP_Endpoint* endp = IsOrig() ? tcp->Orig() : tcp->Resp();
     301 [ #  # ][ #  # ]:          0 :                 if ( endp->state == TCP_ENDPOINT_PARTIAL &&
                 [ #  # ]
     302                 :            :                      endp->LastSeq() - endp->StartSeq() <= 2 )
     303                 :            :                         ; // Ignore it.
     304                 :            :                 else
     305                 :            :                         {
     306         [ #  # ]:          0 :                         if ( Conn()->FlagEvent(NUL_IN_LINE) )
     307                 :          0 :                                 Conn()->Weird("NUL_in_line");
     308                 :          0 :                         flag_NULs = 0;
     309                 :            :                         }
     310                 :            :                 }
     311                 :          0 :         }
     312                 :            : 
     313                 :          0 : void ContentLine_Analyzer::SkipBytesAfterThisLine(int length)
     314                 :            :         {
     315                 :            :         // This is a little complicated because Bro has to handle
     316                 :            :         // both CR and CRLF as a line break. When a line is delivered,
     317                 :            :         // it's possible that only a CR is seen, and we may not know
     318                 :            :         // if an LF is following until we see the next packet.  If an
     319                 :            :         // LF follows, we should start skipping bytes *after* the LF.
     320                 :            :         // So we keep the skip as 'pending' until we see the next
     321                 :            :         // character in DoDeliver().
     322                 :            : 
     323         [ #  # ]:          0 :         if ( last_char == '\r' )
     324                 :          0 :                 skip_pending = length;
     325                 :            :         else
     326                 :          0 :                 SkipBytes(length);
     327                 :          0 :         }
     328                 :            : 
     329                 :          0 : void ContentLine_Analyzer::SkipBytes(int length)
     330                 :            :         {
     331                 :          0 :         skip_pending = 0;
     332                 :          0 :         seq_to_skip = SeqDelivered() + length;
     333 [ +  - ][ +  - ]:          6 :         }
     334                 :          3 : 

Generated by: LCOV version 1.8